<?php

declare(strict_types=1);

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

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Mailer\ReviewInvitationMailer;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Messenger\Messaging\CommandHandlerInterface;
use CpCreation\VitiCore\Marketing\Model\ReviewInvitation;
use CpCreation\VitiCore\Marketing\Repository\ReviewInvitationRepository;
use CpCreation\VitiCore\Marketing\Repository\ReviewRequestConfigurationRepository;
use CpCreation\VitiCore\Marketing\Repository\ReviewSolicitationOptOutRepository;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;

#[AsMessageHandler]
final readonly class ReviewInvitationReminderMailCommandHandler implements CommandHandlerInterface
{
    public function __construct(
        private ReviewInvitationRepository $invitationRepository,
        private ReviewRequestConfigurationRepository $configurationRepository,
        private ReviewSolicitationOptOutRepository $optOutRepository,
        private ReviewInvitationMailer $mailer,
    ) {}

    public function __invoke(ReviewInvitationReminderMailCommand $command): void
    {
        $invitation = $this->invitationRepository->find($command->invitationId);
        if (!$invitation instanceof ReviewInvitation) {
            throw new UnrecoverableMessageHandlingException('Invitation d’avis introuvable.');
        }

        $tokenHash = $invitation->getReminderTokenHash();
        if (null === $tokenHash || !hash_equals($tokenHash, hash('sha256', $command->token))) {
            // Un claim devenu stale peut avoir été remplacé par un nouveau jeton.
            return;
        }

        $now = new \DateTimeImmutable();
        if (!$invitation->canReceiveSecondReminderAt($now)) {
            return;
        }

        if ($this->optOutRepository->hasOptedOut($invitation->getRecipientEmail())) {
            $invitation->suppressReminder($now);
            $this->invitationRepository->save($invitation);

            return;
        }

        $configuration = $this->configurationRepository->findOne();
        if (null === $configuration
            || !$configuration->isEnabled()
            || !$configuration->isSecondReminderEnabled()
        ) {
            return;
        }

        $this->mailer->sendReminder($invitation, $command->token, $configuration);
        $invitation->markReminderSent($now);
        $this->invitationRepository->save($invitation);
    }
}
