<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Notification\Email;

use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\NotificationComment;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendImmediateNotificationEmailMessage;
use Doctrine\ORM\Event\PostPersistEventArgs;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

// use Symfony\Component\Translation\LocaleSwitcher;

readonly class NotificationMailer
{
    public function __construct(
        private MailerInterface $mailer,
        private LoggerInterface $logger,
        private MessageBusInterface $messageBus,
        private TranslatorInterface $translator,
        // private LocaleSwitcher $localeSwitcher,
    ) {}

    public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
    {
        $dests = [
            $comment->getNotification()->getSender(),
            ...$comment->getNotification()->getAddressees()->toArray(),
        ];

        $uniqueDests = [];
        foreach ($dests as $dest) {
            // avoid duplication
            if (in_array(spl_object_hash($dest), $uniqueDests, true)) {
                continue;
            }
            $uniqueDests[] = spl_object_hash($dest);

            // do not send if the sender does not have any email, nor to the creator of the comment
            if (null === $dest->getEmail() || $comment->getCreatedBy() === $dest) {
                continue;
            }
            $email = new TemplatedEmail();
            $email
                ->to($dest->getEmail())
                ->subject('Re: '.$comment->getNotification()->getTitle())
                ->textTemplate('@ChillMain/Notification/email_notification_comment_persist.md.twig')
                ->context([
                    'comment' => $comment,
                    'dest' => $dest,
                ]);

            try {
                $this->mailer->send($email);
            } catch (TransportExceptionInterface $e) {
                $this->logger->warning('[NotificationMailer] could not send an email notification about comment', [
                    'to' => $dest->getEmail(),
                    'error_message' => $e->getMessage(),
                    'error_trace' => $e->getTraceAsString(),
                ]);
            }
        }
    }

    /**
     * Send a email after a notification is persisted.
     */
    public function postPersistNotification(Notification $notification, PostPersistEventArgs $eventArgs): void
    {
        $this->sendNotificationEmailsToAddressees($notification);
        $this->sendNotificationEmailsToAddressesEmails($notification);
    }

    private function sendNotificationEmailsToAddressees(Notification $notification): void
    {
        if ('' === $notification->getType()) {
            $this->logger->warning('[NotificationMailer] Notification has no type, skipping email processing', [
                'notification_id' => $notification->getId(),
            ]);

            return;
        }

        foreach ($notification->getAllAddressees() as $addressee) {
            if (null === $addressee->getEmail()) {
                continue;
            }

            $this->processNotificationForAddressee($notification, $addressee);
        }
    }

    private function processNotificationForAddressee(Notification $notification, User $addressee): void
    {
        $notificationType = $notification->getType();

        if ($addressee->isNotificationSendImmediately($notificationType)) {
            $this->scheduleImmediateEmail($notification, $addressee);
        }
    }

    private function scheduleImmediateEmail(Notification $notification, User $addressee): void
    {
        $message = new SendImmediateNotificationEmailMessage(
            $notification->getId(),
            $addressee->getId()
        );

        $this->messageBus->dispatch($message);

        $this->logger->info('[NotificationMailer] Scheduled immediate email', [
            'notification_id' => $notification->getId(),
            'addressee_email' => $addressee->getEmail(),
        ]);
    }

    /**
     * This method sends the email but is now called by the immediate notification email message handler.
     *
     * @throws TransportExceptionInterface
     */
    public function sendEmailToAddressee(Notification $notification, User $addressee): void
    {
        if (null === $addressee->getEmail()) {
            return;
        }

        // Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
        /*
        $this->localeSwitcher->runWithLocale($addressee->getLocale(), function () use ($notification, $addressee) {
            if ($notification->isSystem()) {
                $email = new Email();
                $email->text($notification->getMessage());
            } else {
                $email = new TemplatedEmail();
                $email
                    ->textTemplate('@ChillMain/Notification/email_non_system_notification_content.md.twig')
                    ->context([
                        'notification' => $notification,
                        'dest' => $addressee,
                    ]);
            }

            $email
                ->subject($notification->getTitle())
                ->to($addressee->getEmail());

            try {
                $this->mailer->send($email);
                $this->logger->info('[NotificationMailer] Email sent successfully', [
                    'notification_id' => $notification->getId(),
                    'addressee_email' => $addressee->getEmail(),
                    'locale' => $addressee->getLocale(),
                ]);
            } catch (TransportExceptionInterface $e) {
                $this->logger->warning('[NotificationMailer] Could not send an email notification', [
                    'to' => $addressee->getEmail(),
                    'notification_id' => $notification->getId(),
                    'error_message' => $e->getMessage(),
                    'error_trace' => $e->getTraceAsString(),
                ]);
                throw $e;
            }
        });
        */

        // Current implementation:
        if ($notification->isSystem()) {
            $email = new Email();
            $email->text($notification->getMessage());
        } else {
            $email = new TemplatedEmail();
            $email
                ->textTemplate('@ChillMain/Notification/email_non_system_notification_content.md.twig')
                ->context([
                    'notification' => $notification,
                    'dest' => $addressee,
                ]);
        }

        $email
            ->subject($notification->getTitle())
            ->to($addressee->getEmail());

        try {
            $this->mailer->send($email);
            $this->logger->info('[NotificationMailer] Email sent successfully', [
                'notification_id' => $notification->getId(),
                'addressee_email' => $addressee->getEmail(),
            ]);
        } catch (TransportExceptionInterface $e) {
            $this->logger->warning('[NotificationMailer] Could not send an email notification', [
                'to' => $addressee->getEmail(),
                'notification_id' => $notification->getId(),
                'error_message' => $e->getMessage(),
                'error_trace' => $e->getTraceAsString(),
            ]);
            throw $e;
        }
    }

    /**
     * Send daily digest email with multiple notifications to a user.
     *
     * @throws TransportExceptionInterface
     */
    public function sendDailyDigest(User $user, array $notifications): void
    {
        if (null === $user->getEmail() || [] === $notifications) {
            return;
        }

        // Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
        /*
        $this->localeSwitcher->runWithLocale($user->getLocale(), function () use ($user, $notifications) {
            $email = new TemplatedEmail();
            $email
                ->htmlTemplate('@ChillMain/Notification/email_daily_digest.md.twig')
                ->context([
                    'user' => $user,
                    'notifications' => $notifications,
                    'notification_count' => count($notifications),
                ])
                ->subject($this->translator->trans('notification.Daily Notification Digest'))
                ->to($user->getEmail());

            try {
                $this->mailer->send($email);
                $this->logger->info('[NotificationMailer] Daily digest email sent successfully', [
                    'user_email' => $user->getEmail(),
                    'notification_count' => count($notifications),
                    'locale' => $user->getLocale(),
                ]);
            } catch (TransportExceptionInterface $e) {
                $this->logger->warning('[NotificationMailer] Could not send daily digest email', [
                    'to' => $user->getEmail(),
                    'notification_count' => count($notifications),
                    'error_message' => $e->getMessage(),
                    'error_trace' => $e->getTraceAsString(),
                ]);
                throw $e;
            }
        });
        */

        // Current implementation:
        $email = new TemplatedEmail();
        $email
            ->htmlTemplate('@ChillMain/Notification/email_daily_digest.md.twig')
            ->context([
                'user' => $user,
                'notifications' => $notifications,
                'notification_count' => count($notifications),
            ])
            ->subject($this->translator->trans('notification.Daily Notification Digest'))
            ->to($user->getEmail());

        try {
            $this->mailer->send($email);
            $this->logger->info('[NotificationMailer] Daily digest email sent successfully', [
                'user_email' => $user->getEmail(),
                'notification_count' => count($notifications),
            ]);
        } catch (TransportExceptionInterface $e) {
            $this->logger->warning('[NotificationMailer] Could not send daily digest email', [
                'to' => $user->getEmail(),
                'notification_count' => count($notifications),
                'error_message' => $e->getMessage(),
                'error_trace' => $e->getTraceAsString(),
            ]);
            throw $e;
        }
    }

    private function sendNotificationEmailsToAddressesEmails(Notification $notification): void
    {
        foreach ($notification->getAddresseeUserGroups() as $userGroup) {

            if (!$userGroup->hasEmail()) {
                continue;
            }

            $emailAddress = $userGroup->getEmail();

            $email = new TemplatedEmail();
            $email
                ->textTemplate('@ChillMain/Notification/email_non_system_notification_content_to_email.md.twig')
                ->context([
                    'notification' => $notification,
                    'dest' => $emailAddress,
                ]);

            $email
                ->subject($notification->getTitle())
                ->to($emailAddress);

            try {
                $this->mailer->send($email);
            } catch (TransportExceptionInterface $e) {
                $this->logger->warning('[NotificationMailer] could not send an email notification', [
                    'to' => $emailAddress,
                    'error_message' => $e->getMessage(),
                    'error_trace' => $e->getTraceAsString(),
                ]);
            }
        }
    }
}
