<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Monolog;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\MessengerLog;
use Ferienpass\CoreBundle\Entity\SentEmail;
use Ferienpass\CoreBundle\Notifier\Mime\NotificationEmail;
use Ferienpass\CoreBundle\Repository\ConversationItemRepository;
use Ferienpass\CoreBundle\Repository\MessengerLogRepository;
use Ferienpass\CoreBundle\Repository\UserRepository;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Level;
use Monolog\LogRecord;
use Symfony\Component\Uid\Uuid;

class NotificationLogHandler extends AbstractProcessingHandler
{
    public function __construct(private readonly MessengerLogRepository $logs, private readonly UserRepository $users, private readonly ConversationItemRepository $conversations, private readonly EntityManagerInterface $entityManager, int|string|Level $level = Level::Debug, bool $bubble = true)
    {
        parent::__construct($level, $bubble);
    }

    protected function write(LogRecord $record): void
    {
        $context = $record->context;
        if (!$context['email'] instanceof NotificationEmail) {
            return;
        }

        /** @var MessengerLog|null $messageLog */
        $messageLog = $this->logs->findOneBy(['uuid' => $context['email']->getBelongsTo()]);

        $log = SentEmail::fromNotificationEmail($context['email'], $context['messageId'] ?? '');
        $log->setLogEntry($messageLog);

        // Tie the sent email to the conversation it opened or belongs to, so the
        // Postausgang can render replies threaded under it. Set only when the
        // referenced item still exists (it is committed before the mail goes out).
        $conversationUuid = $context['email']->getConversationItem();
        if (null !== $conversationUuid && Uuid::isValid($conversationUuid)) {
            $log->setConversation($this->conversations->find(Uuid::fromString($conversationUuid)));
        }

        $this->entityManager->persist($log);

        // Guess the user by the email recipient. Their name is denormalised onto the
        // sent mail so the Postausgang can search and list recipients by name without
        // walking log→users for every row.
        $user = $this->users->findOneBy(['email' => ($context['email']->getTo()[0] ?? null)?->getAddress()]);
        if (null !== $user) {
            $log->setToName($user->getName());

            $messageLog?->addUser($user);
        }

        if ($this->entityManager->getConnection()->isTransactionActive()) {
            return;
        }

        $this->entityManager->flush();
    }
}
