<?php

namespace App\EventSubscriber;

use App\Entity\MessengerLog;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
use Symfony\Component\Mime\Email;

class MessengerFailureSubscriber implements EventSubscriberInterface
{
    public function __construct(
        private EntityManagerInterface $em,
        private MailerInterface $mailer,
        #[\Symfony\Component\DependencyInjection\Attribute\Autowire('%admin_email%')] private string $adminEmail,
    ) {
    }

    public static function getSubscribedEvents(): array
    {
        return [
            WorkerMessageFailedEvent::class => 'onMessageFailed',
        ];
    }

    public function onMessageFailed(WorkerMessageFailedEvent $event): void
    {
        $envelope = $event->getEnvelope();
        $message = $envelope->getMessage();
        $throwable = $event->getThrowable();

        $retryCount = 0;
        $redeliveryStamp = $envelope->last(RedeliveryStamp::class);
        if ($redeliveryStamp instanceof RedeliveryStamp) {
            $retryCount = $redeliveryStamp->getRetryCount();
        }

        $messageBody = null;
        try {
            $messageBody = serialize($message);
        } catch (\Throwable) {
            $messageBody = get_class($message).' (not serializable)';
        }

        $log = new MessengerLog(
            messageClass: get_class($message),
            messageBody: $messageBody,
            errorMessage: $throwable->getMessage(),
            stackTrace: $throwable->getTraceAsString(),
            transportName: $event->getReceiverName(),
            retryCount: $retryCount,
        );

        $this->em->persist($log);
        $this->em->flush();

        try {
            $email = (new Email())
                ->from($this->adminEmail)
                ->to($this->adminEmail)
                ->subject('Alerte Messenger : Echec de traitement')
                ->priority(Email::PRIORITY_HIGH)
                ->text(
                    "Un message Messenger a echoue.\n\n".
                    'Message: '.get_class($message)."\n".
                    'Transport: '.$event->getReceiverName()."\n".
                    'Retry: '.$retryCount."\n".
                    'Erreur: '.$throwable->getMessage()."\n\n".
                    "Stack trace:\n".$throwable->getTraceAsString()
                );

            $this->mailer->send($email);
        } catch (\Throwable $e) {
            error_log('Failed to send messenger alert email: '.$e->getMessage());
        }
    }
}
