<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\Controller\Trait;

use MauticPlugin\DealFlowBundle\Controller\DealFormController;
use MauticPlugin\DealFlowBundle\Controller\DealListController;
use MauticPlugin\DealFlowBundle\Controller\DealViewController;
use MauticPlugin\DealFlowBundle\Controller\ReportController;
use MauticPlugin\DealFlowBundle\Controller\StageController;
use MauticPlugin\DealFlowBundle\Entity\Deal;
use MauticPlugin\DealFlowBundle\Service\AutomationOptionsProvider;
use MauticPlugin\DealFlowBundle\Service\DefaultPipelineInitializer;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Form-related helpers shared across deal form controllers.
 *
 * Requires the using class to extend CommonController (for generateUrl,
 * delegateRedirect, postActionRedirect, container access).
 */
trait DealFormHelpersTrait
{
    /**
     * @return array{url: string, contentTemplate: string, viewParameters: array<string, mixed>}
     */
    private function resolveReturnContext(Request $request, string $defaultRoute, array $defaultRouteParameters = []): array
    {
        $defaultUrl = $this->generateUrl($defaultRoute, $defaultRouteParameters);
        $returnUrl = (string) $this->getRequestValue($request, 'returnUrl', $defaultUrl);
        $parsedUrl = parse_url($returnUrl);
        $path = $parsedUrl['path'] ?? $defaultUrl;
        $query = [];

        if (isset($parsedUrl['query'])) {
            parse_str($parsedUrl['query'], $query);
        }

        unset(
            $query['_'],
            $query['ignoreAjax'],
            $query['mauticUserLastActive'],
            $query['mauticLastNotificationId'],
            $query['modal'],
            $query['contentOnly']
        );

        $returnUrl = $path.([] !== $query ? '?'.http_build_query($query) : '');

        $routeParameters = $defaultRouteParameters;
        $routeName = $defaultRoute;

        try {
            $matchedRoute = $this->container->get('router')->match($path);
            $routeName = $matchedRoute['_route'] ?? $defaultRoute;
            unset($matchedRoute['_route'], $matchedRoute['_controller']);
            $routeParameters = array_merge($routeParameters, $matchedRoute);
        } catch (\Throwable) {
        }

        // Target the real rendering sub-controllers, NOT the DealController facade.
        // The facade's actions forward() to these sub-controllers, and that nested
        // sub-request is re-detected as ajax — so rendering the facade as a modal
        // contentTemplate dumps a raw JSON-in-JSON payload into the page. The
        // sub-controllers below terminate in delegateView() and render HTML directly.
        $contentTemplate = match ($routeName) {
            'mautic_dealflow_index' => DealListController::class.'::indexAction',
            'mautic_dealflow_view' => DealViewController::class.'::viewAction',
            'mautic_dealflow_edit',
            'mautic_dealflow_edit_legacy' => DealFormController::class.'::editAction',
            'mautic_dealflow_reports' => ReportController::class.'::indexAction',
            'mautic_dealflow_stage_index' => StageController::class.'::indexAction',
            default => DealListController::class.'::pipelineAction',
        };

        return [
            'url' => $returnUrl,
            'contentTemplate' => $contentTemplate,
            'viewParameters' => array_merge($routeParameters, $query),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function buildFormActionParameters(Request $request, string $returnUrl): array
    {
        $parameters = ['returnUrl' => $returnUrl];

        if ($this->isModalRequest($request)) {
            $parameters['modal'] = 1;
            $parameters['contentOnly'] = 1;
        }

        return $parameters;
    }

    /**
     * @param array{url: string, contentTemplate: string, viewParameters: array<string, mixed>} $returnContext
     */
    private function finishDealForm(Request $request, array $returnContext): Response
    {
        if ($this->isModalRequest($request)) {
            return $this->postActionRedirect([
                'returnUrl' => $returnContext['url'],
                'contentTemplate' => $returnContext['contentTemplate'],
                'viewParameters' => $returnContext['viewParameters'],
                'passthroughVars' => [
                    'closeModal' => true,
                    'route' => $returnContext['url'],
                    'mauticContent' => 'dealflow',
                ],
            ]);
        }

        return $this->delegateRedirect($returnContext['url']);
    }

    private function isModalRequest(Request $request): bool
    {
        return (bool) $this->getRequestValue($request, 'modal', false);
    }

    private function shouldCloseAfterSubmit(Request $request): bool
    {
        return !$this->isApplyRequest($request);
    }

    private function isApplyRequest(Request $request): bool
    {
        return array_key_exists('apply', $this->getSubmittedButtons($request));
    }

    private function isCancelRequest(Request $request): bool
    {
        return array_key_exists('cancel', $this->getSubmittedButtons($request));
    }

    /**
     * @return array<string, mixed>
     */
    private function getSubmittedButtons(Request $request): array
    {
        $formData = $request->request->all('deal');
        $buttons = $formData['buttons'] ?? [];

        return is_array($buttons) ? $buttons : [];
    }

    private function getRequestValue(Request $request, string $key, mixed $default = null): mixed
    {
        if ($request->query->has($key)) {
            return $request->query->get($key);
        }

        if ($request->attributes->has($key)) {
            return $request->attributes->get($key);
        }

        return $default;
    }

    /**
     * @return list<\MauticPlugin\DealFlowBundle\Entity\DealStage>
     */
    private function buildStageChoices(DefaultPipelineInitializer $pipelineInitializer): array
    {
        $stages = [];

        foreach ($pipelineInitializer->getActivePipelines() as $pipeline) {
            foreach ($pipelineInitializer->getOrderedStages($pipeline, true) as $stage) {
                $stages[] = $stage;
            }
        }

        return $stages;
    }

    /**
     * @return array<string, string>
     */
    private function buildSourceChoices(AutomationOptionsProvider $automationOptionsProvider, ?string $currentSource): array
    {
        $choices = $automationOptionsProvider->getSourceChoices($currentSource);
        $choices['Add new source...'] = '__new__';

        return $choices;
    }

    /**
     * @return array<string, string>
     */
    private function buildCurrencyChoices(?string $currentCurrency): array
    {
        $choices = [
            'USD' => 'USD',
            'EUR' => 'EUR',
            'GBP' => 'GBP',
            'CAD' => 'CAD',
            'AUD' => 'AUD',
            'JPY' => 'JPY',
            'CHF' => 'CHF',
        ];

        $currentCurrency = strtoupper(trim((string) $currentCurrency));
        if ('' !== $currentCurrency && !array_key_exists($currentCurrency, $choices)) {
            $choices = [$currentCurrency => $currentCurrency] + $choices;
        }

        return $choices;
    }

    private function resolveSourceSelection(?string $currentSource, array $sourceChoices): ?string
    {
        $currentSource = trim((string) $currentSource);
        if ('' === $currentSource) {
            return null;
        }

        return array_key_exists($currentSource, $sourceChoices) ? $currentSource : '__new__';
    }

    private function applySourceSelection(\Symfony\Component\Form\FormInterface $form, Deal $deal): void
    {
        $sourceSelection = trim((string) $form->get('sourceSelection')->getData());
        $newSource = trim((string) $form->get('sourceNew')->getData());

        if ('__new__' === $sourceSelection) {
            if ('' === $newSource) {
                $form->get('sourceNew')->addError(new FormError('Enter a source name or choose an existing source.'));

                return;
            }

            $deal->setSource($newSource);

            return;
        }

        $deal->setSource('' !== $sourceSelection ? $sourceSelection : null);
    }

    private function validatePipelineStageSelection(\Symfony\Component\Form\FormInterface $form, Deal $deal): bool
    {
        $pipeline = $deal->getPipeline();
        $stage = $deal->getStage();

        if (null !== $pipeline && null !== $stage && $stage->getPipeline()?->getId() !== $pipeline->getId()) {
            $form->get('stage')->addError(new FormError('Select a stage from the selected pipeline.'));

            return false;
        }

        return true;
    }
}
