<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\Controller;

use Doctrine\Persistence\ManagerRegistry;
use Mautic\CoreBundle\Controller\CommonController;
use MauticPlugin\DealFlowBundle\Controller\Helper\DealRequestParser;
use MauticPlugin\DealFlowBundle\Controller\Trait\DealFormHelpersTrait;
use MauticPlugin\DealFlowBundle\Controller\Trait\OwnerChoicesTrait;
use MauticPlugin\DealFlowBundle\Controller\Trait\QueryParamTrait;
use MauticPlugin\DealFlowBundle\Entity\Deal;
use MauticPlugin\DealFlowBundle\Entity\DealRepository;
use MauticPlugin\DealFlowBundle\Form\Type\DealType;
use MauticPlugin\DealFlowBundle\Model\DealModel;
use MauticPlugin\DealFlowBundle\Service\AutomationOptionsProvider;
use MauticPlugin\DealFlowBundle\Service\DealAuthorization;
use MauticPlugin\DealFlowBundle\Service\DealContextBuilder;
use MauticPlugin\DealFlowBundle\Service\DealFieldManager;
use MauticPlugin\DealFlowBundle\Service\DefaultPipelineInitializer;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Handles deal create/edit form actions.
 * Consumed by DealController (facade) — do not register routes here directly.
 */
final class DealFormController extends CommonController
{
    use DealFormHelpersTrait;
    use OwnerChoicesTrait;
    use QueryParamTrait;

    public function newAction(
        Request $request,
        DealAuthorization $authorization,
        FormFactoryInterface $formFactory,
        ManagerRegistry $managerRegistry,
        DefaultPipelineInitializer $pipelineInitializer,
        DealModel $dealModel,
        DealFieldManager $dealFieldManager,
        AutomationOptionsProvider $automationOptionsProvider,
    ): Response {
        if (!$authorization->canCreateDeals()) {
            return $this->accessDenied();
        }

        $isModal = $this->isModalRequest($request);
        $pipeline = $pipelineInitializer->resolvePipeline($this->queryNullableInt($request, 'pipelineId'));
        $activePipelines = $pipelineInitializer->getActivePipelines();
        $stageChoices = $this->buildStageChoices($pipelineInitializer);
        $returnContext = $this->resolveReturnContext($request, 'mautic_dealflow_pipeline', ['pipelineId' => $pipeline->getId()]);
        $deal = new Deal();
        $deal->setPipeline($pipeline);
        $customFieldDefinitions = $dealFieldManager->getActiveFields();
        $customFieldValues = $dealFieldManager->getFormValues($deal, $customFieldDefinitions);
        $customFieldErrors = [];
        $sourceChoices = $this->buildSourceChoices($automationOptionsProvider, $deal->getSource());
        $contactRows = DealRequestParser::ensureContactRows([]);
        $contactRowErrors = [];
        $roleSuggestions = array_values($automationOptionsProvider->getStakeholderRoleChoices());

        $stages = $pipelineInitializer->getOrderedStages($pipeline, true);
        if ([] !== $stages) {
            $deal->setStage($stages[0]);
        }

        $form = $formFactory->create(DealType::class, $deal, [
            'pipeline_choices' => $activePipelines,
            'stage_choices' => $stageChoices,
            'owner_choices' => $this->buildOwnerChoices($managerRegistry, $deal->getOwnerId()),
            'source_choices' => $sourceChoices,
            'currency_choices' => $this->buildCurrencyChoices($deal->getCurrency()),
            'current_source_selection' => $this->resolveSourceSelection($deal->getSource(), $sourceChoices),
            'current_source_new' => null,
        ]);
        $formAction = $this->generateUrl('mautic_dealflow_new', array_merge(
            ['pipelineId' => $pipeline->getId()],
            $this->buildFormActionParameters($request, $returnContext['url'])
        ));
        $form->handleRequest($request);

        if ($this->isCancelRequest($request)) {
            return $this->finishDealForm($request, $returnContext);
        }

        if ($form->isSubmitted()) {
            $customFieldValues = DealRequestParser::resolveCustomFieldInputs($request);
            $normalizedCustomFields = $dealFieldManager->normalizeSubmittedValues($customFieldValues, $customFieldDefinitions);
            $customFieldErrors = $normalizedCustomFields['errors'];
            $contactRows = DealRequestParser::resolveSubmittedContactRows($request);
            $contactRowErrors = DealRequestParser::validateContactRows($contactRows);
            $this->applySourceSelection($form, $deal);

            if ('' === trim((string) $deal->getTitle())) {
                $form->get('title')->addError(new FormError('Deal title is required.'));
            }

            if ([] === $customFieldErrors) {
                $deal->setCustomFields($dealFieldManager->mergeStoredValues($deal->getCustomFields(), $normalizedCustomFields['values'], $customFieldDefinitions));
            }
        }

        if ($form->isSubmitted() && $form->isValid() && [] === $customFieldErrors && [] === $contactRowErrors && $this->validatePipelineStageSelection($form, $deal)) {
            $dealModel->saveEntity($deal);
            $dealModel->getDealManager()->syncContactAssociations($deal, DealRequestParser::buildContactSyncPayload($contactRows), $this->user?->getId(), 'ui');

            if ($this->shouldCloseAfterSubmit($request)) {
                return $this->finishDealForm($request, $returnContext);
            }

            if (!$authorization->canEditDeal($deal) && !$authorization->canViewDeal($deal)) {
                return $this->finishDealForm($request, $returnContext);
            }

            $nextRoute = $authorization->canEditDeal($deal) ? 'mautic_dealflow_edit' : 'mautic_dealflow_view';
            $nextUrl = $this->generateUrl($nextRoute, array_merge(
                ['objectId' => $deal->getId(), 'pipelineId' => $deal->getPipeline()?->getId()],
                'mautic_dealflow_edit' === $nextRoute ? $this->buildFormActionParameters($request, $returnContext['url']) : []
            ));

            if ($isModal) {
                return $this->postActionRedirect([
                    'returnUrl' => $nextUrl,
                    // Target the real rendering sub-controllers, not the forwarding DealController facade.
                    'contentTemplate' => 'mautic_dealflow_edit' === $nextRoute ? self::class.'::editAction' : DealViewController::class.'::viewAction',
                    'viewParameters' => [
                        'objectId' => $deal->getId(),
                        'modal' => 1,
                        'contentOnly' => 1,
                        'returnUrl' => $returnContext['url'],
                    ],
                    'passthroughVars' => [
                        'route' => $nextUrl,
                        'mauticContent' => 'dealflow',
                    ],
                ]);
            }

            return $this->delegateRedirect($nextUrl);
        }

        return $this->delegateView([
            'viewParameters' => [
                'form' => $form->createView(),
                'pageTitle' => 'New Deal',
                'cancelUrl' => $returnContext['url'],
                'formAction' => $formAction,
                'isModal' => $isModal,
                'addUserUrl' => $this->generateUrl('mautic_user_action', ['objectAction' => 'new']),
                'customFieldDefinitions' => $customFieldDefinitions,
                'customFieldValues' => $customFieldValues,
                'customFieldErrors' => $customFieldErrors,
                'contactRows' => $contactRows,
                'contactRowErrors' => $contactRowErrors,
                'roleSuggestions' => $roleSuggestions,
            ],
            'contentTemplate' => '@DealFlow/Deal/form.html.twig',
            'passthroughVars' => [
                'activeLink' => '#mautic_dealflow_new',
                'route' => $formAction,
                'mauticContent' => 'dealflow',
            ],
        ]);
    }

    public function editAction(
        int $objectId,
        Request $request,
        DealAuthorization $authorization,
        FormFactoryInterface $formFactory,
        ManagerRegistry $managerRegistry,
        DealRepository $dealRepository,
        DefaultPipelineInitializer $pipelineInitializer,
        DealModel $dealModel,
        DealFieldManager $dealFieldManager,
        DealContextBuilder $contextBuilder,
        AutomationOptionsProvider $automationOptionsProvider,
    ): Response {
        $isModal = $this->isModalRequest($request);
        $deal = $dealRepository->find($objectId);
        if (!$deal instanceof Deal) {
            throw $this->createNotFoundException(sprintf('Deal %d not found.', $objectId));
        }

        if (!$authorization->canEditDeal($deal)) {
            return $this->accessDenied();
        }

        $activePipelines = $pipelineInitializer->getActivePipelines();
        $stageChoices = $this->buildStageChoices($pipelineInitializer);
        $returnContext = $this->resolveReturnContext($request, 'mautic_dealflow_view', ['objectId' => $deal->getId()]);
        $previousStage = $deal->getStage();
        $previousOwnerId = $deal->getOwnerId();
        $previousCompanyId = $deal->getCompanyId();
        $previousStatus = $deal->getStatus();
        $dealModel->setPreviousState($previousStage, $previousOwnerId, $previousCompanyId, $previousStatus);
        $customFieldDefinitions = $dealFieldManager->getActiveFields();
        $customFieldValues = $dealFieldManager->getFormValues($deal, $customFieldDefinitions);
        $customFieldErrors = [];
        $sourceChoices = $this->buildSourceChoices($automationOptionsProvider, $deal->getSource());
        $contactRows = DealRequestParser::buildContactRowsFromContext($contextBuilder->buildForDeal($deal)['contacts']);
        $contactRowErrors = [];
        $roleSuggestions = array_values($automationOptionsProvider->getStakeholderRoleChoices());

        $form = $formFactory->create(DealType::class, $deal, [
            'pipeline_choices' => $activePipelines,
            'stage_choices' => $stageChoices,
            'owner_choices' => $this->buildOwnerChoices($managerRegistry, $deal->getOwnerId()),
            'source_choices' => $sourceChoices,
            'currency_choices' => $this->buildCurrencyChoices($deal->getCurrency()),
            'current_source_selection' => $this->resolveSourceSelection($deal->getSource(), $sourceChoices),
            'current_source_new' => null,
        ]);
        $formAction = $this->generateUrl('mautic_dealflow_edit', array_merge(
            ['objectId' => $deal->getId()],
            $this->buildFormActionParameters($request, $returnContext['url'])
        ));
        $form->handleRequest($request);

        if ($this->isCancelRequest($request)) {
            return $this->finishDealForm($request, $returnContext);
        }

        if ($form->isSubmitted()) {
            $customFieldValues = DealRequestParser::resolveCustomFieldInputs($request);
            $normalizedCustomFields = $dealFieldManager->normalizeSubmittedValues($customFieldValues, $customFieldDefinitions);
            $customFieldErrors = $normalizedCustomFields['errors'];
            $contactRows = DealRequestParser::resolveSubmittedContactRows($request);
            $contactRowErrors = DealRequestParser::validateContactRows($contactRows);
            $this->applySourceSelection($form, $deal);

            if ('' === trim((string) $deal->getTitle())) {
                $form->get('title')->addError(new FormError('Deal title is required.'));
            }

            if ([] === $customFieldErrors) {
                $deal->setCustomFields($dealFieldManager->mergeStoredValues($deal->getCustomFields(), $normalizedCustomFields['values'], $customFieldDefinitions));
            }
        }

        if ($form->isSubmitted() && $form->isValid() && [] === $customFieldErrors && [] === $contactRowErrors && $this->validatePipelineStageSelection($form, $deal)) {
            $dealModel->saveEntity($deal);
            $dealModel->getDealManager()->syncContactAssociations($deal, DealRequestParser::buildContactSyncPayload($contactRows), $this->user?->getId(), 'ui');

            if ($this->shouldCloseAfterSubmit($request)) {
                return $this->finishDealForm($request, $returnContext);
            }

            if ($isModal) {
                return $this->postActionRedirect([
                    'returnUrl' => $formAction,
                    // Target the real rendering sub-controller (self), not the forwarding facade.
                    'contentTemplate' => self::class.'::editAction',
                    'viewParameters' => [
                        'objectId' => $deal->getId(),
                        'modal' => 1,
                        'contentOnly' => 1,
                        'returnUrl' => $returnContext['url'],
                    ],
                    'passthroughVars' => [
                        'route' => $formAction,
                        'mauticContent' => 'dealflow',
                    ],
                ]);
            }

            return $this->delegateRedirect($formAction);
        }

        return $this->delegateView([
            'viewParameters' => [
                'form' => $form->createView(),
                'pageTitle' => 'Edit Deal',
                'cancelUrl' => $returnContext['url'],
                'formAction' => $formAction,
                'isModal' => $isModal,
                'addUserUrl' => $this->generateUrl('mautic_user_action', ['objectAction' => 'new']),
                'customFieldDefinitions' => $customFieldDefinitions,
                'customFieldValues' => $customFieldValues,
                'customFieldErrors' => $customFieldErrors,
                'contactRows' => $contactRows,
                'contactRowErrors' => $contactRowErrors,
                'roleSuggestions' => $roleSuggestions,
            ],
            'contentTemplate' => '@DealFlow/Deal/form.html.twig',
            'passthroughVars' => [
                'activeLink' => '#mautic_dealflow_pipeline',
                'route' => $formAction,
                'mauticContent' => 'dealflow',
            ],
        ]);
    }
}
