<?php

namespace App\Domain\Scraping\Application\CommandHandler;

use App\Domain\Scraping\Application\Command\TestScraperConfiguration;
use App\Domain\Scraping\Application\Response\TestScraperConfigurationResponse;
use App\Domain\Scraping\Domain\Contract\Service\ScraperInterface;
use App\Domain\Scraping\Domain\Contract\Service\ScraperFactoryInterface;
use App\Domain\Scraping\Domain\Model\ValueObject\ScrapingRequest;

readonly class TestScraperConfigurationHandler
{
    public function __construct(
        private ScraperFactoryInterface $scraperFactory
    ) {
    }

    public function handle(TestScraperConfiguration $command): TestScraperConfigurationResponse
    {
        // Construction des paramètres de scraping depuis les données de la commande
        $scrapingParameters = [
            'imageSelector' => $command->imageSelector,
            'nextPageSelector' => $command->nextPageSelector,
            'chapterUrlFormat' => $command->chapterUrlFormat,
            'scrapingType' => $command->scrapingType,
            'chapterSelector' => $command->chapterSelector,
            'chapterNumber' => $command->chapterNumber
        ];
        // Vérification que le scraper supporte le type de scraping
        if (!$this->scraperFactory->isSupported($command->scrapingType)) {
            return $this->tryWithFallbackScrapers($command, $scrapingParameters);
        }

        // Essayer avec le scraper demandé
        try {
            $scraper = $this->scraperFactory->createScraper($command->scrapingType);
            $scrapingRequest = new ScrapingRequest(
                $command->scrapingType,
                $command->testUrl,
                $scrapingParameters
            );

            $scrapingResult = $scraper->scrape($scrapingRequest);


            return TestScraperConfigurationResponse::success(
                $scrapingResult->getImageUrls(),
                $command->testUrl,
                $command->scrapingType
            );

        } catch (\Exception $e) {
            return TestScraperConfigurationResponse::failure(
                $command->testUrl,
                $command->scrapingType,
                $this->analyzeError($e, $command)
            );
        }
    }

    private function tryWithFallbackScrapers(
        TestScraperConfiguration $command,
        array $scrapingParameters,
        ?\Exception $originalException = null
    ): TestScraperConfigurationResponse {
        $errors = [];

        if ($originalException) {
            $errors[] = [
                'type' => 'primary_scraper_failed',
                'scraper' => $command->scrapingType,
                'message' => $originalException->getMessage()
            ];
        }

        // Essayer avec tous les scrapers disponibles
        $availableScrapers = $this->scraperFactory->getSupportedTypes();
        $triedScrapers = [];

        foreach ($availableScrapers as $scraperType) {
            if ($scraperType === $command->scrapingType) {
                continue; // Déjà essayé
            }

            try {
                $scraper = $this->scraperFactory->createScraper($scraperType);
                $scrapingRequest = new ScrapingRequest(
                    $scraperType,
                    $command->testUrl,
                    $scrapingParameters
                );

                $scrapingResult = $scraper->scrape($scrapingRequest);

                // Succès avec un scraper alternatif
                return TestScraperConfigurationResponse::success(
                    $scrapingResult->getImageUrls(),
                    $command->testUrl,
                    $scraperType, // Retourner le type de scraper qui a fonctionné
                    "Scraper alternatif utilisé: {$scraperType} (au lieu de {$command->scrapingType})"
                );

            } catch (\Exception $e) {
                $triedScrapers[] = $scraperType;
                $errors[] = [
                    'type' => 'fallback_scraper_failed',
                    'scraper' => $scraperType,
                    'message' => $e->getMessage()
                ];
            }
        }

        // Tous les scrapers ont échoué
        $errors[] = [
            'type' => 'all_scrapers_failed',
            'message' => 'Aucun scraper disponible n\'a réussi à traiter cette URL',
            'tried_scrapers' => array_merge([$command->scrapingType], $triedScrapers)
        ];

        return TestScraperConfigurationResponse::failure(
            $command->testUrl,
            $command->scrapingType,
            $errors
        );
    }

    private function analyzeError(\Exception $e, TestScraperConfiguration $command): array
    {
        $errors = [];
        $message = $e->getMessage();

        // Erreurs liées aux sélecteurs
        if (str_contains($message, 'imageSelector') || str_contains($message, 'filter')) {
            $errors[] = [
                'type' => 'selector_error',
                'field' => 'imageSelector',
                'message' => "Le sélecteur d'image '{$command->imageSelector}' ne trouve aucun élément sur la page",
                'suggestion' => "Vérifiez que le sélecteur CSS est correct et qu'il correspond aux éléments d'image sur la page"
            ];
        }

        // Erreurs liées à l'URL
        if (str_contains($message, 'Failed to fetch HTML') || str_contains($message, 'Chapter Not Found')) {
            $errors[] = [
                'type' => 'url_error',
                'field' => 'testUrl',
                'message' => "Impossible d'accéder à l'URL de test: {$command->testUrl}",
                'suggestion' => "Vérifiez que l'URL est correcte et accessible, et que le chapitre existe"
            ];
        }

        // Erreurs liées aux sélecteurs de navigation
        if (str_contains($message, 'nextPageSelector')) {
            $errors[] = [
                'type' => 'selector_error',
                'field' => 'nextPageSelector',
                'message' => "Le sélecteur de page suivante '{$command->nextPageSelector}' pose problème",
                'suggestion' => "Vérifiez le sélecteur CSS pour la navigation entre les pages"
            ];
        }

        // Erreur générique si aucune erreur spécifique n'est détectée
        if (empty($errors)) {
            $errors[] = [
                'type' => 'general_error',
                'field' => 'configuration',
                'message' => $message,
                'suggestion' => "Vérifiez l'ensemble de la configuration et l'accessibilité du site web"
            ];
        }

        return $errors;
    }
}
