<?php

declare(strict_types=1);

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

use CpCreation\VitiCore\Contact\Repository\ContactRepository;
use CpCreation\VitiCore\Marketing\Model\ReviewInvitation;
use CpCreation\VitiCore\Marketing\Model\ReviewRequestConfiguration;
use Symfony\Component\Mailer\Transport\TransportInterface;
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 ReviewInvitationMailer
{
    public function __construct(
        private TransportInterface $transport,
        private ContactRepository $contactRepository,
        private TranslatorInterface $translator,
        private Environment $twig,
        private UrlGeneratorInterface $urlGenerator,
    ) {}

    public function send(
        ReviewInvitation $invitation,
        string $token,
        ReviewRequestConfiguration $configuration,
    ): void {
        $this->sendEmail($invitation, $token, $configuration, false);
    }

    public function sendReminder(
        ReviewInvitation $invitation,
        string $token,
        ReviewRequestConfiguration $configuration,
    ): void {
        $this->sendEmail($invitation, $token, $configuration, true);
    }

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

        $company = (string) $contact->getCompany();
        $testToken = str_repeat('T', 43);
        $subject = $this->translator->trans(
            'marketing.review_request.mail.subject',
            ['%company%' => $company],
            'messages',
            $locale,
        );
        $emailTitle = $configuration->getEmailTitleForLocale($locale)
            ?? $this->translator->trans(
                'marketing.review_request.mail.heading',
                [],
                'messages',
                $locale,
            );
        $context = [
            'contact' => $contact,
            'company' => $company,
            'email_title' => $emailTitle,
            'cart' => [
                'id' => '00000000-0000-0000-0000-000000000000',
                'token' => 'TEST-AVIS',
                'items' => [[
                    'quantity' => 2,
                    'variant' => [
                        'fullName' => $this->translator->trans(
                            'marketing.test_email.fake.review_product',
                            [],
                            'messages',
                            $locale,
                        ),
                        'product' => null,
                    ],
                ]],
            ],
            'review_url' => $this->urlGenerator->generate('shop_review_invitation', [
                '_locale' => $locale,
                'token' => $testToken,
            ], UrlGeneratorInterface::ABSOLUTE_URL),
            'opt_out_url' => $this->urlGenerator->generate('shop_review_solicitation_opt_out', [
                '_locale' => $locale,
                'token' => $testToken,
            ], UrlGeneratorInterface::ABSOLUTE_URL),
            'review_policy_url' => $this->urlGenerator->generate('shop_review_policy', [
                '_locale' => $locale,
            ], UrlGeneratorInterface::ABSOLUTE_URL),
            'google_business_review_url' => $configuration->getGoogleBusinessReviewUrl(),
            'expires_at' => new \DateTimeImmutable('+90 days'),
            'locale' => $locale,
            'is_reminder' => false,
        ];

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

        EmailLogMetadata::attachForDirectTransport($email, 'review_invitation_test');
        $this->transport->send($email);
    }

    private function sendEmail(
        ReviewInvitation $invitation,
        string $token,
        ReviewRequestConfiguration $configuration,
        bool $isReminder,
    ): void {
        $contact = $this->contactRepository->findOne();
        if (null === $contact) {
            throw new \RuntimeException('Aucun contact boutique n’est configuré pour envoyer les invitations d’avis.');
        }

        $cart = $invitation->getCart();
        $locale = $cart->getLocale();
        $company = $contact->getCompany();
        $reviewUrl = $this->urlGenerator->generate('shop_review_invitation', [
            '_locale' => $locale,
            'token' => $token,
        ], UrlGeneratorInterface::ABSOLUTE_URL);
        $optOutUrl = $this->urlGenerator->generate('shop_review_solicitation_opt_out', [
            '_locale' => $locale,
            'token' => $token,
        ], UrlGeneratorInterface::ABSOLUTE_URL);
        $reviewPolicyUrl = $this->urlGenerator->generate('shop_review_policy', [
            '_locale' => $locale,
        ], UrlGeneratorInterface::ABSOLUTE_URL);
        $emailTitle = $configuration->getEmailTitleForLocale($locale)
            ?? $this->translator->trans(
                $isReminder
                    ? 'marketing.review_request.mail.reminder_heading'
                    : 'marketing.review_request.mail.heading',
                [],
                'messages',
                $locale,
            );

        $email = new Email()
            ->subject($this->translator->trans(
                $isReminder
                    ? 'marketing.review_request.mail.reminder_subject'
                    : 'marketing.review_request.mail.subject',
                ['%company%' => $company],
                'messages',
                $locale,
            ))
            ->from(new Address($contact->getEmailFrom(), $company))
            ->sender($contact->getEmailFrom())
            ->returnPath($contact->getEmailFrom())
            ->to($invitation->getRecipientEmail())
            ->html($this->twig->render('mail/review_invitation.html.twig', [
                'contact' => $contact,
                'company' => $company,
                'email_title' => $emailTitle,
                'cart' => $cart,
                'review_url' => $reviewUrl,
                'opt_out_url' => $optOutUrl,
                'review_policy_url' => $reviewPolicyUrl,
                'google_business_review_url' => $configuration->getGoogleBusinessReviewUrl(),
                'expires_at' => $invitation->getExpiresAt(),
                'locale' => $locale,
                'is_reminder' => $isReminder,
            ]))
            ->text($this->twig->render('mail/review_invitation.txt.twig', [
                'company' => $company,
                'email_title' => $emailTitle,
                'cart' => $cart,
                'review_url' => $reviewUrl,
                'opt_out_url' => $optOutUrl,
                'review_policy_url' => $reviewPolicyUrl,
                'google_business_review_url' => $configuration->getGoogleBusinessReviewUrl(),
                'expires_at' => $invitation->getExpiresAt(),
                'locale' => $locale,
                'is_reminder' => $isReminder,
            ]));

        EmailLogMetadata::attachForDirectTransport(
            $email,
            $isReminder ? 'review_invitation_reminder' : 'review_invitation',
            $cart->getUser(),
            $cart,
        );
        // Cette classe est appelée depuis une commande Messenger déjà asynchrone.
        // L’envoi direct permet de ne marquer l’invitation comme envoyée qu’après
        // acceptation par le transport SMTP, sans seconde file d’attente imbriquée.
        $this->transport->send($email);
    }
}
