<?php

namespace App\Domain\Setting\Infrastructure\Persistence\Repository;

use App\Domain\Scraping\Domain\Contract\Repository\ContentSourceForHealthCheckInterface;
use App\Domain\Scraping\Domain\Contract\Repository\ContentSourceHealthRepositoryInterface;
use App\Domain\Scraping\Domain\Model\ValueObject\ContentSourceHealthCheckData;
use App\Entity\ContentSource as ContentSourceEntity;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;

readonly class DoctrineContentSourceForHealthCheckRepository implements ContentSourceForHealthCheckInterface, ContentSourceHealthRepositoryInterface
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private HubInterface $hub,
        private LoggerInterface $logger,
    ) {
    }

    public function getAll(): array
    {
        $entities = $this->entityManager->getRepository(ContentSourceEntity::class)->findAll();

        return array_map(
            fn (ContentSourceEntity $entity) => new ContentSourceHealthCheckData(
                id: $entity->getId(),
                baseUrl: $entity->getBaseUrl(),
                chapterUrlFormat: $entity->getChapterUrlFormat(),
                scrapingType: $entity->getScrapingType(),
                imageSelector: $entity->getImageSelector(),
                nextPageSelector: $entity->getNextPageSelector(),
                chapterSelector: $entity->getChapterSelector(),
                testSlug: $entity->getTestSlug(),
                testChapterNumber: $entity->getTestChapterNumber(),
            ),
            $entities
        );
    }

    public function markAsTesting(int $sourceId): void
    {
        $entity = $this->entityManager->find(ContentSourceEntity::class, $sourceId);
        if (!$entity) {
            return;
        }

        $entity->setHealthStatus('testing')
               ->setHealthLastError(null);

        $this->entityManager->flush();
        $this->publishUpdate($sourceId, 'testing', null);
    }

    public function markAsHealthy(int $sourceId, \DateTimeImmutable $testedAt): void
    {
        $entity = $this->entityManager->find(ContentSourceEntity::class, $sourceId);
        if (!$entity) {
            return;
        }

        $entity->setHealthStatus('ok')
               ->setHealthLastTestedAt($testedAt)
               ->setHealthLastError(null);

        $this->entityManager->flush();
        $this->publishUpdate($sourceId, 'ok', null);
    }

    public function markAsUnhealthy(int $sourceId, \DateTimeImmutable $testedAt, string $error): void
    {
        $entity = $this->entityManager->find(ContentSourceEntity::class, $sourceId);
        if (!$entity) {
            return;
        }

        $entity->setHealthStatus('ko')
               ->setHealthLastTestedAt($testedAt)
               ->setHealthLastError($error);

        $this->entityManager->flush();
        $this->publishUpdate($sourceId, 'ko', $error);
    }

    private function publishUpdate(int $sourceId, string $status, ?string $error): void
    {
        try {
            $this->hub->publish(new Update(
                "scrapers/health/{$sourceId}",
                json_encode(['sourceId' => $sourceId, 'status' => $status, 'error' => $error])
            ));
        } catch (\Throwable $e) {
            $this->logger->warning('Mercure publish failed for scraper health update', [
                'sourceId' => $sourceId,
                'status' => $status,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
