<?php

namespace App\Domain\Scraping\Infrastructure\EventSubscriber;

use App\Domain\Shared\Domain\Event\ChapterScraped;
use App\Domain\Scraping\Domain\Event\ChapterScrapingFailed;
use App\Domain\Scraping\Domain\Event\ChapterScrapingStarted;
use App\Domain\Scraping\Domain\Event\PageScrapingProgressed;
use App\Domain\Scraping\Domain\Contract\Repository\ChapterRepositoryInterface;
use App\Domain\Shared\Domain\Contract\JobRepositoryInterface;
use App\Domain\Shared\Domain\Contract\NotificationInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

class ScrapingEventSubscriber implements EventSubscriberInterface
{
    public function __construct(
        private readonly HubInterface $hub,
        private readonly ChapterRepositoryInterface $chapterRepository,
        private readonly JobRepositoryInterface $jobRepository,
        private readonly NotificationInterface $notification,
        private readonly LoggerInterface $logger
    ) {
    }

    public static function getSubscribedEvents(): array
    {
        return [];
    }

    #[AsMessageHandler]
    public function onPageScrapingProgressed(PageScrapingProgressed $event): void
    {
        $progress = (int) round($event->getProgress()->getPercentage());

        $update = new Update(
            'jobs/activity',
            json_encode([
                'type'     => 'job.progress_updated',
                'jobId'    => $event->getJobId(),
                'progress' => $progress,
            ])
        );
        $this->hub->publish($update);
    }

    #[AsMessageHandler]
    public function onChapterScrapingStarted(ChapterScrapingStarted $event): void
    {
        $chapterNumber = $event->getChapterNumber();
        $mangaTitle = $event->getMangaTitle();

        $this->notification->sendInfo(
            sprintf('Scraping du chapitre %s de "%s" démarré', $chapterNumber, $mangaTitle)
        );
    }

    #[AsMessageHandler]
    public function onChapterScraped(ChapterScraped $event): void
    {
        $jobId = $event->getJobId();
        $this->logger->info('ChapterScraped reçu pour le job: ' . $jobId);

        $job = $this->jobRepository->get($jobId);

        if (!$job) {
            $this->logger->warning('Job non trouvé pour l\'ID: ' . $jobId);
            return;
        }

        $chapterId = $job->context['chapterId'] ?? null;
        $this->logger->info('ChapterId extrait du job: ' . $chapterId);

        $chapter = $this->chapterRepository->getById($chapterId);

        if (!$chapter) {
            $this->logger->warning('Chapitre non trouvé pour l\'ID: ' . $chapterId);
            return;
        }

        $this->logger->info('Chapitre trouvé - ID: ' . $chapter->id . ', MangaId: ' . $chapter->mangaId . ', Number: ' . $chapter->chapterNumber);

        $data = [
            'type' => 'chapter.scraped',
            'chapterId' => $chapter->id,
            'mangaId' => $chapter->mangaId,
            'chapterNumber' => $chapter->chapterNumber,
            'isAvailable' => true,
            'timestamp' => (new \DateTimeImmutable())->format('c')
        ];

        $topics = [
            'manga/chapter/' . $chapter->id,
            'manga/' . $chapter->mangaId . '/chapters',
            'scraping/status'
        ];

        $update = new Update($topics, json_encode($data));
        $this->hub->publish($update);

        $mangaTitle = $job->context['mangaTitle'] ?? 'manga inconnu';
        $this->notification->sendSuccess(
            sprintf('Chapitre %s de "%s" scrappé avec succès', $chapter->chapterNumber, $mangaTitle)
        );
    }

    #[AsMessageHandler]
    public function onChapterScrapingFailed(ChapterScrapingFailed $event): void
    {
        $this->logger->info('ChapterScrapingFailed reçu pour mangaId: ' . $event->getMangaId() . ', chapter: ' . $event->getChapterNumber());

        $data = [
            'type' => 'chapter.scraping.failed',
            'mangaId' => $event->getMangaId(),
            'chapterNumber' => $event->getChapterNumber(),
            'reason' => $event->getReason(),
            'timestamp' => (new \DateTimeImmutable())->format('c')
        ];

        $topics = [
            'manga/' . $event->getMangaId() . '/chapters',
            'scraping/status'
        ];

        $update = new Update($topics, json_encode($data));
        $this->hub->publish($update);

        $this->notification->sendError(
            sprintf('Échec du scraping du chapitre %s : %s', $event->getChapterNumber(), $event->getReason())
        );
    }
}
