<?php

namespace App\Domain\Scraping\Infrastructure\Service;

use App\Domain\Scraping\Domain\Contract\Service\ScraperInterface;
use App\Domain\Scraping\Domain\Contract\Service\ScraperFactoryInterface;
use App\Domain\Scraping\Infrastructure\Service\Scraper\HtmlScraper;
use App\Domain\Scraping\Infrastructure\Service\Scraper\AdvancedHtmlScraper;
use App\Domain\Scraping\Infrastructure\Service\Scraper\JavaScriptScraper;
use App\Domain\Scraping\Domain\Contract\Service\ImageDownloaderInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class ScraperFactory implements ScraperFactoryInterface
{
    private const SCRAPER_TYPES = [
        'html' => HtmlScraper::class,
        'advanced_html' => AdvancedHtmlScraper::class,
        'javascript' => JavaScriptScraper::class,
    ];

    private const SCRAPER_PRIORITIES = [
        'javascript' => 1,      // Le plus puissant pour contourner les protections
        'advanced_html' => 2,   // Bon compromis entre performance et efficacité
        'html' => 3,           // Le plus simple et rapide
    ];

    private array $scrapers = [];

    public function __construct(
        private readonly ImageDownloaderInterface $imageDownloader,
        private readonly MessageBusInterface $eventBus,
        private readonly HttpClientInterface $httpClient,
        private readonly string $projectDir
    ) {
        $this->initializeScrapers();
    }

    /**
     * Créer un scraper pour un type spécifique
     */
    public function createScraper(string $type): ScraperInterface
    {
        if (!isset($this->scrapers[$type])) {
            throw new \InvalidArgumentException("Scraper type '{$type}' is not supported");
        }

        return $this->scrapers[$type];
    }

    /**
     * Obtenir le scraper le plus approprié selon la priorité
     */
    public function getBestScraper(): ScraperInterface
    {
        $sortedTypes = array_keys(self::SCRAPER_PRIORITIES);
        usort($sortedTypes, fn ($a, $b) => self::SCRAPER_PRIORITIES[$a] <=> self::SCRAPER_PRIORITIES[$b]);

        return $this->scrapers[$sortedTypes[0]];
    }

    /**
     * Obtenir tous les scrapers disponibles
     */
    public function getAvailableScrapers(): array
    {
        return $this->scrapers;
    }

    /**
     * Obtenir les types de scrapers supportés
     */
    public function getSupportedTypes(): array
    {
        return array_keys(self::SCRAPER_TYPES);
    }

    /**
     * Vérifier si un type de scraper est supporté
     */
    public function isSupported(string $type): bool
    {
        return isset(self::SCRAPER_TYPES[$type]);
    }

    /**
     * Obtenir le scraper de fallback (le plus simple)
     */
    public function getFallbackScraper(): ScraperInterface
    {
        return $this->scrapers['html'];
    }

    /**
     * Essayer plusieurs scrapers en cascade jusqu'à ce qu'un fonctionne
     */
    public function getScraperWithFallback(string $preferredType): ScraperInterface
    {
        // Essayer le type préféré d'abord
        if ($this->isSupported($preferredType)) {
            return $this->scrapers[$preferredType];
        }

        // Fallback vers le scraper par défaut
        return $this->getFallbackScraper();
    }

    /**
     * Obtenir des statistiques sur les scrapers
     */
    public function getScraperStats(): array
    {
        return [
            'total_scrapers' => count($this->scrapers),
            'supported_types' => $this->getSupportedTypes(),
            'priorities' => self::SCRAPER_PRIORITIES,
            'best_scraper' => $this->getBestScraper()::class,
            'fallback_scraper' => $this->getFallbackScraper()::class
        ];
    }

    private function initializeScrapers(): void
    {
        foreach (self::SCRAPER_TYPES as $type => $class) {
            $this->scrapers[$type] = $this->createScraperInstance($class);
        }
    }

    private function createScraperInstance(string $class): ScraperInterface
    {
        return match ($class) {
            HtmlScraper::class => new HtmlScraper(
                $this->imageDownloader,
                $this->eventBus,
                $this->httpClient
            ),
            AdvancedHtmlScraper::class => new AdvancedHtmlScraper(
                $this->httpClient
            ),
            JavaScriptScraper::class => new JavaScriptScraper(
                $this->projectDir
            ),
            default => throw new \InvalidArgumentException("Unknown scraper class: {$class}")
        };
    }
}
