<?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 Doctrine\ORM\Event\PostPersistEventArgs;
use Doctrine\ORM\Event\PostUpdateEventArgs;
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\Contracts\Translation\TranslatorInterface;

class NotificationMailer
{
    public function __construct(private readonly MailerInterface $mailer, private readonly LoggerInterface $logger, private readonly TranslatorInterface $translator) {}

    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.fr.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->sendNotificationEmailsToAddresses($notification);
        $this->sendNotificationEmailsToAddressesEmails($notification);
    }

    public function postUpdateNotification(Notification $notification, PostUpdateEventArgs $eventArgs): void
    {
        $this->sendNotificationEmailsToAddressesEmails($notification);
    }

    private function sendNotificationEmailsToAddresses(Notification $notification): void
    {
        foreach ($notification->getAddressees() as $addressee) {
            if (null === $addressee->getEmail()) {
                continue;
            }

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

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

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

    private function sendNotificationEmailsToAddressesEmails(Notification $notification): void
    {
        foreach ($notification->getAddressesEmailsAdded() as $emailAddress) {
            $email = new TemplatedEmail();
            $email
                ->textTemplate('@ChillMain/Notification/email_non_system_notification_content_to_email.fr.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(),
                ]);
            }
        }
    }
}
