<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer;

use CpCreation\VitiCore\Cart\CartPromo;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Contact\Repository\ContactRepository;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartConfiguration;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartReminder;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;

final readonly class AbandonedCartReminderMailer
{
    public function __construct(
        private MailerInterface $mailer,
        private ContactRepository $contactRepository,
        private TranslatorInterface $translator,
        private Environment $twig,
        private UrlGeneratorInterface $urlGenerator,
    ) {}

    public function send(AbandonedCartReminder $reminder, string $token): void
    {
        $contact = $this->contactRepository->findOne();
        if (null === $contact) {
            throw new \RuntimeException('Aucun contact boutique n’est configuré pour envoyer les relances de panier.');
        }

        $cart = $reminder->getCart();
        $locale = $cart->getLocale();
        $company = $contact->getCompany();
        $configuration = $reminder->getRule()->getConfiguration();
        $emailSubject = $configuration->getEmailSubjectForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.subject',
                [],
                'messages',
                $locale,
            );
        $emailPreheader = $configuration->getEmailPreheaderForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.preheader',
                [],
                'messages',
                $locale,
            );
        $emailTitle = $configuration->getEmailTitleForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.heading',
                [],
                'messages',
                $locale,
            );
        $cartSubtotalTTC = 0;
        foreach ($cart->getItems() as $item) {
            $cartSubtotalTTC += max(0, $item->getTotalFinalTTC());
        }
        $catalogDiscountTTC = $this->catalogDiscountTTC($cart);
        $degressiveDiscountTTC = max(0, $cart->getPricing()?->degressiveTTC ?? 0);
        $existingCartPromos = $this->existingCartPromos($reminder);
        $hasExistingCartDiscounts = $catalogDiscountTTC > 0 || $degressiveDiscountTTC > 0;
        foreach ($existingCartPromos as $existingCartPromo) {
            if ($existingCartPromo->getDiscountTotalTTC() > 0) {
                $hasExistingCartDiscounts = true;
                break;
            }
        }

        $recoveryUrl = $this->urlGenerator->generate('shop_abandoned_cart_recovery', [
            '_locale' => $locale,
            'token' => $token,
        ], UrlGeneratorInterface::ABSOLUTE_URL);
        $context = [
            'contact' => $contact,
            'company' => $company,
            'email_title' => $emailTitle,
            'email_subject' => $emailSubject,
            'email_preheader' => $emailPreheader,
            'cart' => $cart,
            'cart_subtotal_ttc' => $cartSubtotalTTC,
            'cart_catalog_discount_ttc' => $catalogDiscountTTC,
            'cart_degressive_discount_ttc' => $degressiveDiscountTTC,
            'cart_degressive_is_bottle_offered' => $cart->getPricing()?->degressiveIsBottleOffered ?? false,
            'existing_cart_promos' => $existingCartPromos,
            'has_existing_cart_discounts' => $hasExistingCartDiscounts,
            'reminder' => $reminder,
            'promo' => $reminder->getPromo(),
            'recovery_url' => $recoveryUrl,
            'expires_at' => $reminder->getExpiresAt(),
            'locale' => $locale,
        ];

        $email = new Email()
            ->subject($emailSubject)
            ->from(new Address($contact->getEmailFrom(), $company))
            ->sender($contact->getEmailFrom())
            ->returnPath($contact->getEmailFrom())
            ->to($reminder->getRecipientEmail())
            ->html($this->twig->render('mail/abandoned_cart_reminder.html.twig', $context))
            ->text($this->twig->render('mail/abandoned_cart_reminder.txt.twig', $context));

        EmailLogMetadata::attach($email, 'abandoned_cart_reminder', $cart->getUser(), $cart);
        $this->mailer->send($email);
    }

    public function sendTest(
        string $recipientEmail,
        AbandonedCartConfiguration $configuration,
        string $locale = 'fr',
    ): void {
        $contact = $this->contactRepository->findOne();
        if (null === $contact) {
            throw new \RuntimeException('Aucun contact boutique n’est configuré pour envoyer les relances de panier.');
        }

        $company = (string) $contact->getCompany();
        $emailSubject = $configuration->getEmailSubjectForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.subject',
                [],
                'messages',
                $locale,
            );
        $emailPreheader = $configuration->getEmailPreheaderForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.preheader',
                [],
                'messages',
                $locale,
            );
        $emailTitle = $configuration->getEmailTitleForLocale($locale)
            ?? $this->translator->trans(
                'marketing.abandoned_cart.mail.heading',
                [],
                'messages',
                $locale,
            );
        $context = [
            'contact' => $contact,
            'company' => $company,
            'email_title' => $emailTitle,
            'email_subject' => $emailSubject,
            'email_preheader' => $emailPreheader,
            'cart' => [
                'items' => [[
                    'quantity' => 2,
                    'selectedOptionName' => null,
                    'finalPriceTTC' => 3600,
                    'totalFinalTTC' => 7200,
                    'variant' => [
                        'fullName' => $this->translator->trans(
                            'marketing.test_email.fake.cart_product',
                            [],
                            'messages',
                            $locale,
                        ),
                        'product' => null,
                    ],
                ]],
            ],
            'cart_subtotal_ttc' => 7200,
            'cart_catalog_discount_ttc' => 0,
            'cart_degressive_discount_ttc' => 0,
            'cart_degressive_is_bottle_offered' => false,
            'existing_cart_promos' => [],
            'has_existing_cart_discounts' => false,
            'reminder' => null,
            'promo' => [
                'title' => $this->translator->trans(
                    'marketing.test_email.fake.promo_code',
                    [],
                    'messages',
                    $locale,
                ),
                'amountTTC' => null,
                'percent' => 0.1,
                'percentShippingCost' => null,
            ],
            'recovery_url' => $this->urlGenerator->generate('shop_abandoned_cart_recovery', [
                '_locale' => $locale,
                'token' => str_repeat('T', 43),
            ], UrlGeneratorInterface::ABSOLUTE_URL),
            'expires_at' => new \DateTimeImmutable('+7 days'),
            'locale' => $locale,
        ];

        $email = new Email()
            ->subject($this->translator->trans(
                'marketing.test_email.subject',
                ['%subject%' => $emailSubject],
                'messages',
                $locale,
            ))
            ->from(new Address($contact->getEmailFrom(), $company))
            ->sender($contact->getEmailFrom())
            ->returnPath($contact->getEmailFrom())
            ->to($recipientEmail)
            ->html($this->twig->render('mail/abandoned_cart_reminder.html.twig', $context))
            ->text($this->twig->render('mail/abandoned_cart_reminder.txt.twig', $context));

        EmailLogMetadata::attach($email, 'abandoned_cart_reminder_test');
        $this->mailer->send($email);
    }

    private function catalogDiscountTTC(Cart $cart): int
    {
        $discountTTC = 0;

        foreach ($cart->getItems() as $item) {
            if (!$item->isDiscounted()) {
                continue;
            }

            $discountTTC += max(0, $item->getTotalDiscountAmount());
        }

        return $discountTTC;
    }

    /**
     * @return list<CartPromo>
     */
    private function existingCartPromos(AbandonedCartReminder $reminder): array
    {
        $generatedPromoId = $reminder->getPromo()?->getId()->toString();

        return array_values(array_filter(
            $reminder->getCart()->getPromos(),
            static fn(CartPromo $promo): bool => null === $generatedPromoId || $promo->promoId !== $generatedPromoId,
        ));
    }
}
