<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Controller\Admin;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Admin\AbandonedCartConfigurationType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Admin\AbandonedCartRuleType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer\AbandonedCartReminderMailer;
use CpCreation\VitiCore\Contact\Repository\ContactRepository;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartConfiguration;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartReminder;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartRule;
use CpCreation\VitiCore\Marketing\Repository\AbandonedCartConfigurationRepository;
use CpCreation\VitiCore\Marketing\Repository\AbandonedCartReminderRepository;
use CpCreation\VitiCore\Marketing\Repository\AbandonedCartRuleRepository;
use CpCreation\VitiCore\Product\Repository\ProductPriceGroupRepository;
use Knp\Component\Pager\PaginatorInterface;
use Psr\Log\LoggerInterface;
use Ramsey\Uuid\Uuid;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/marketing/paniers-abandonnes')]
#[IsGranted(new Expression("is_granted('ROLE_ADMIN') or is_granted('ROLE_MARKETING')"))]
final class AbandonedCartController extends AbstractController
{
    private const int PAGE_SIZE = 50;

    public function __construct(
        private readonly AbandonedCartConfigurationRepository $configurationRepository,
        private readonly AbandonedCartRuleRepository $ruleRepository,
        private readonly AbandonedCartReminderRepository $reminderRepository,
        private readonly ProductPriceGroupRepository $priceGroupRepository,
        private readonly ContactRepository $contactRepository,
        private readonly AbandonedCartReminderMailer $mailer,
        private readonly PaginatorInterface $paginator,
        private readonly TranslatorInterface $translator,
        private readonly LoggerInterface $logger,
    ) {}

    #[Route('', name: 'admin_marketing_abandoned_cart', methods: ['GET', 'POST'])]
    public function index(Request $request): Response
    {
        $persistedConfiguration = $this->configurationRepository->findOne();
        $configuration = $persistedConfiguration ?? new AbandonedCartConfiguration();
        $form = $this->createForm(AbandonedCartConfigurationType::class, $configuration);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->configurationRepository->save($configuration);
            $this->addFlash('alert-success', $this->translator->trans('marketing.abandoned_cart.configuration.saved'));

            return $this->redirectToRoute('admin_marketing_abandoned_cart');
        }

        return $this->render('@CpCreationVitiCore/admin/marketing/abandoned_cart/index.html.twig', [
            'configuration' => $configuration,
            'form' => $form->createView(),
            'rules' => null !== $persistedConfiguration
                ? $this->ruleRepository->findForConfiguration($persistedConfiguration)
                : [],
            'reminder_count' => $this->reminderRepository->count([]),
            'test_email_recipient' => $this->contactRepository->findOne()?->getEmailToMessage() ?? '',
        ]);
    }

    #[Route('/email-test', name: 'admin_marketing_abandoned_cart_test_email', methods: ['POST'])]
    public function sendTestEmail(Request $request): Response
    {
        if (!$this->isCsrfTokenValid('marketing-abandoned-cart-test-email', $request->request->getString('_token'))) {
            throw $this->createAccessDeniedException();
        }

        $recipientEmail = mb_trim($request->request->getString('email'));
        if (false === filter_var($recipientEmail, \FILTER_VALIDATE_EMAIL)) {
            $this->addFlash('alert-danger', $this->translator->trans('marketing.test_email.invalid'));

            return $this->redirectToRoute('admin_marketing_abandoned_cart');
        }

        try {
            $this->mailer->sendTest(
                $recipientEmail,
                $this->configurationRepository->findOne() ?? new AbandonedCartConfiguration(),
            );
            $this->addFlash('alert-success', $this->translator->trans(
                'marketing.test_email.sent',
                ['%email%' => $recipientEmail],
            ));
        } catch (\Throwable $exception) {
            $this->logger->error('Échec de l’envoi d’un email de test de panier abandonné.', [
                'exception' => $exception,
                'recipient' => $recipientEmail,
            ]);
            $this->addFlash('alert-danger', $this->translator->trans('marketing.test_email.failed'));
        }

        return $this->redirectToRoute('admin_marketing_abandoned_cart');
    }

    #[Route('/relances', name: 'admin_marketing_abandoned_cart_reminders', methods: ['GET'])]
    public function reminders(Request $request): Response
    {
        $filters = $this->resolveReminderFilters($request);
        $configuration = $this->configurationRepository->findOne();

        return $this->render('@CpCreationVitiCore/admin/marketing/abandoned_cart/reminders.html.twig', [
            'reminders' => $this->paginator->paginate(
                $this->reminderRepository->createAdminQueryBuilder(
                    '' !== $filters['search'] ? $filters['search'] : null,
                    '' !== $filters['status'] ? $filters['status'] : null,
                    '' !== $filters['rule'] ? $filters['rule'] : null,
                ),
                max(1, $request->query->getInt('page', 1)),
                self::PAGE_SIZE,
            ),
            'rules' => null !== $configuration
                ? $this->ruleRepository->findForConfiguration($configuration)
                : [],
            'statuses' => AbandonedCartReminder::STATUSES,
            'filters' => $filters,
            'has_filters' => '' !== $filters['search']
                || '' !== $filters['status']
                || '' !== $filters['rule'],
        ]);
    }

    #[Route('/regles/nouvelle', name: 'admin_marketing_abandoned_cart_rule_new', methods: ['GET', 'POST'])]
    public function newRule(Request $request): Response
    {
        $configuration = $this->configurationRepository->findOne();
        if (null === $configuration) {
            $configuration = new AbandonedCartConfiguration();
            $this->configurationRepository->save($configuration);
        }

        $rule = new AbandonedCartRule($configuration);
        $rule->setPosition(\count($this->ruleRepository->findForConfiguration($configuration)));
        $rule->setPriceGroup($this->priceGroupRepository->getGroupByDefault());

        return $this->handleRuleForm($rule, $request);
    }

    #[Route('/regles/{id}/modifier', name: 'admin_marketing_abandoned_cart_rule_edit', methods: ['GET', 'POST'])]
    public function editRule(AbandonedCartRule $rule, Request $request): Response
    {
        $configuration = $this->configurationRepository->findOne();
        if (null === $configuration || !$rule->getConfiguration()->getId()->equals($configuration->getId())) {
            throw $this->createNotFoundException();
        }

        return $this->handleRuleForm($rule, $request);
    }

    #[Route('/regles/{id}/supprimer', name: 'admin_marketing_abandoned_cart_rule_delete', methods: ['POST'])]
    public function deleteRule(AbandonedCartRule $rule, Request $request): Response
    {
        if (!$this->isCsrfTokenValid('delete-abandoned-cart-rule-' . $rule->getId()->toString(), (string) $request->request->get('_token'))) {
            throw $this->createAccessDeniedException();
        }

        if ($this->reminderRepository->countForRule($rule) > 0) {
            $this->addFlash('alert-danger', $this->translator->trans('marketing.abandoned_cart.rule.delete_used'));
        } else {
            $this->ruleRepository->delete($rule);
            $this->addFlash('alert-success', $this->translator->trans('marketing.abandoned_cart.rule.deleted'));
        }

        return $this->redirectToRoute('admin_marketing_abandoned_cart');
    }

    private function handleRuleForm(AbandonedCartRule $rule, Request $request): Response
    {
        $isNew = null === $this->ruleRepository->find($rule->getId());
        $form = $this->createForm(AbandonedCartRuleType::class, $rule);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->ruleRepository->save($rule);
            $this->addFlash('alert-success', $this->translator->trans('marketing.abandoned_cart.rule.saved'));

            return $this->redirectToRoute('admin_marketing_abandoned_cart');
        }

        return $this->render('@CpCreationVitiCore/admin/marketing/abandoned_cart/rule.html.twig', [
            'rule' => $rule,
            'is_new' => $isNew,
            'form' => $form->createView(),
        ]);
    }

    /**
     * @return array{search: string, status: string, rule: string}
     */
    private function resolveReminderFilters(Request $request): array
    {
        $search = mb_substr(mb_trim($request->query->getString('search')), 0, 200);
        $status = mb_trim($request->query->getString('status'));
        $rule = mb_trim($request->query->getString('rule'));

        return [
            'search' => $search,
            'status' => \in_array($status, AbandonedCartReminder::STATUSES, true) ? $status : '',
            'rule' => Uuid::isValid($rule) ? $rule : '',
        ];
    }
}
