<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Mailer;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer\AbandonedCartReminderMailer;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer\EmailLogMetadata;
use CpCreation\VitiCore\Cart\CartPromo;
use CpCreation\VitiCore\Cart\CartPromos;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\CartItem;
use CpCreation\VitiCore\Cart\Model\Promo;
use CpCreation\VitiCore\Contact\Model\Contact;
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\Model\Translation\AbandonedCartConfigurationTranslation;
use CpCreation\VitiCore\Product\Model\ProductPrice;
use CpCreation\VitiCore\Product\Model\ProductPriceGroup;
use CpCreation\VitiCore\Product\Model\ProductVariant;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;

final class AbandonedCartReminderMailerTest extends TestCase
{
    public function testTestEmailUsesFakeCartAndRequestedRecipient(): void
    {
        $contact = new Contact();
        $contact->setCompany('Domaine Exemple');
        $contact->setEmailFrom('contact@example.com');

        $contactRepository = $this->createMock(ContactRepository::class);
        $contactRepository->method('findOne')->willReturn($contact);

        $configuration = new AbandonedCartConfiguration();
        $translation = $configuration->translate('fr');
        self::assertInstanceOf(AbandonedCartConfigurationTranslation::class, $translation);
        $translation->setEmailTitle('Retrouvez vos coups de cœur');
        $translation->setEmailSubject('Votre panier personnalisé 🛒');
        $translation->setEmailPreheader('Votre sélection vous attend.');

        $renderedContexts = [];
        $twig = $this->createMock(Environment::class);
        $twig->method('render')->willReturnCallback(
            static function (string $template, array $context) use (&$renderedContexts): string {
                $renderedContexts[$template] = $context;

                return $template;
            },
        );

        $translator = $this->createMock(TranslatorInterface::class);
        $translator->method('trans')->willReturnCallback(
            static fn(string $id, array $parameters = []): string => match ($id) {
                'marketing.test_email.subject' => '[TEST] ' . $parameters['%subject%'],
                'marketing.test_email.fake.cart_product' => 'Cuvée Brut Tradition 75 cl',
                'marketing.test_email.fake.promo_code' => 'TEST10',
                default => $id,
            },
        );

        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('https://example.test/panier/reprise');

        $sentEmail = null;
        $symfonyMailer = $this->createMock(MailerInterface::class);
        $symfonyMailer->expects(self::once())
            ->method('send')
            ->willReturnCallback(static function (Email $email) use (&$sentEmail): void {
                $sentEmail = $email;
            });

        $mailer = new AbandonedCartReminderMailer(
            $symfonyMailer,
            $contactRepository,
            $translator,
            $twig,
            $urlGenerator,
        );
        $mailer->sendTest('admin@example.com', $configuration);

        self::assertInstanceOf(Email::class, $sentEmail);
        self::assertSame('admin@example.com', $sentEmail->getTo()[0]->getAddress());
        self::assertSame('[TEST] Votre panier personnalisé 🛒', $sentEmail->getSubject());
        self::assertSame(
            'abandoned_cart_reminder_test',
            EmailLogMetadata::read($sentEmail)['type'] ?? null,
        );
        self::assertCount(2, $renderedContexts);
        foreach ($renderedContexts as $context) {
            self::assertSame('Cuvée Brut Tradition 75 cl', $context['cart']['items'][0]['variant']['fullName']);
            self::assertSame('Retrouvez vos coups de cœur', $context['email_title']);
            self::assertSame(7200, $context['cart_subtotal_ttc']);
            self::assertSame('TEST10', $context['promo']['title']);
        }
    }

    public function testGeneratedReminderCouponIsExcludedFromExistingCartDiscounts(): void
    {
        $contact = new Contact();
        $contact->setCompany('Domaine Exemple');
        $contact->setEmailFrom('contact@example.com');

        $contactRepository = $this->createMock(ContactRepository::class);
        $contactRepository->method('findOne')->willReturn($contact);

        $generatedPromo = new Promo();
        $generatedPromo->setTitle('PANIER-RELANCE');

        $cart = new Cart();
        $cart->setLocale('fr');
        $cart->setCartPromos(new CartPromos([
            new CartPromo(
                code: 'PANIER-RELANCE',
                promoId: $generatedPromo->getId()->toString(),
                discountItemsTTC: 1000,
            ),
            new CartPromo(
                code: 'FIDELITE',
                promoId: 'existing-promo',
                discountItemsTTC: 500,
            ),
        ]));

        $now = new \DateTimeImmutable('2026-07-23');
        $configuration = new AbandonedCartConfiguration();
        $translation = $configuration->translate('fr');
        self::assertInstanceOf(AbandonedCartConfigurationTranslation::class, $translation);
        $translation->setEmailSubject('Votre panier personnalisé 🛒');
        $translation->setEmailPreheader('Votre sélection personnalisée vous attend ✨');
        $reminder = new AbandonedCartReminder(
            cart: $cart,
            rule: new AbandonedCartRule($configuration),
            promo: $generatedPromo,
            recipientEmail: 'client@example.com',
            tokenHash: hash('sha256', 'token'),
            scheduledAt: $now,
            expiresAt: $now->modify('+7 days'),
        );

        $renderedContexts = [];
        $twig = $this->createMock(Environment::class);
        $twig->method('render')->willReturnCallback(
            static function (string $template, array $context) use (&$renderedContexts): string {
                $renderedContexts[$template] = $context;

                return $template;
            },
        );

        $translator = $this->createMock(TranslatorInterface::class);
        $translator->method('trans')->willReturn('Votre panier vous attend');

        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('https://example.test/panier/reprise');

        $sentEmail = null;
        $symfonyMailer = $this->createMock(MailerInterface::class);
        $symfonyMailer->expects(self::once())
            ->method('send')
            ->willReturnCallback(static function (Email $email) use (&$sentEmail): void {
                $sentEmail = $email;
            });

        $mailer = new AbandonedCartReminderMailer(
            $symfonyMailer,
            $contactRepository,
            $translator,
            $twig,
            $urlGenerator,
        );
        $mailer->send($reminder, 'token');

        self::assertInstanceOf(Email::class, $sentEmail);
        self::assertSame('Votre panier personnalisé 🛒', $sentEmail->getSubject());
        self::assertCount(2, $renderedContexts);
        foreach ($renderedContexts as $context) {
            self::assertSame('Votre panier personnalisé 🛒', $context['email_subject']);
            self::assertSame('Votre sélection personnalisée vous attend ✨', $context['email_preheader']);
            self::assertTrue($context['has_existing_cart_discounts']);
            self::assertCount(1, $context['existing_cart_promos']);
            self::assertSame('FIDELITE', $context['existing_cart_promos'][0]->code);
            self::assertSame($generatedPromo, $context['promo']);
        }
    }

    public function testUndiscountedItemsAreNotReportedAsCatalogDiscounts(): void
    {
        $contact = new Contact();
        $contact->setCompany('Domaine Exemple');
        $contact->setEmailFrom('contact@example.com');

        $contactRepository = $this->createMock(ContactRepository::class);
        $contactRepository->method('findOne')->willReturn($contact);

        $priceGroup = new ProductPriceGroup();
        $priceGroup->setByDefault(true);

        $price = new ProductPrice();
        $price->setGroup($priceGroup);
        $price->setPrice(91520);
        $price->setPriceDiscount(null);

        $variant = new ProductVariant();
        $variant->setGroupAvailable($priceGroup);
        $variant->addPrice($price);

        $item = new CartItem();
        $item->setVariant($variant);

        $cart = new Cart();
        $cart->setLocale('fr');
        $cart->addItem($item);

        $now = new \DateTimeImmutable('2026-07-23');
        $reminder = new AbandonedCartReminder(
            cart: $cart,
            rule: new AbandonedCartRule(new AbandonedCartConfiguration()),
            promo: null,
            recipientEmail: 'client@example.com',
            tokenHash: hash('sha256', 'token'),
            scheduledAt: $now,
            expiresAt: $now->modify('+7 days'),
        );

        $renderedContexts = [];
        $twig = $this->createMock(Environment::class);
        $twig->method('render')->willReturnCallback(
            static function (string $template, array $context) use (&$renderedContexts): string {
                $renderedContexts[$template] = $context;

                return $template;
            },
        );

        $translator = $this->createMock(TranslatorInterface::class);
        $translator->method('trans')->willReturnCallback(
            static fn(string $id): string => match ($id) {
                'marketing.abandoned_cart.mail.subject' => 'Votre panier vous attend',
                'marketing.abandoned_cart.mail.preheader' => 'Finalisez votre commande en quelques instants.',
                default => $id,
            },
        );

        $urlGenerator = $this->createMock(UrlGeneratorInterface::class);
        $urlGenerator->method('generate')->willReturn('https://example.test/panier/reprise');

        $mailer = new AbandonedCartReminderMailer(
            $this->createMock(MailerInterface::class),
            $contactRepository,
            $translator,
            $twig,
            $urlGenerator,
        );
        $mailer->send($reminder, 'token');

        self::assertCount(2, $renderedContexts);
        foreach ($renderedContexts as $context) {
            self::assertSame('Votre panier vous attend', $context['email_subject']);
            self::assertSame(
                'Finalisez votre commande en quelques instants.',
                $context['email_preheader'],
            );
            self::assertSame(91520, $context['cart_subtotal_ttc']);
            self::assertSame(0, $context['cart_catalog_discount_ttc']);
            self::assertFalse($context['has_existing_cart_discounts']);
        }
    }
}
