<?php

namespace App\MessageHandler;

use App\Entity\SargassumObservation;
use App\Message\IngestionScheduleMessage;
use App\Service\Forecast\DriftSimulationService;
use App\Service\Forecast\ImpactScoreService;
use App\Service\Ingestion\IngestionService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Process\Process;

/**
 * Exécute le pipeline complet à chaque tick du scheduler :
 *   1. Ingestion Sentinel-2/3 pour chaque zone Antilles
 *   2. Calcul des forecasts de dérive pour les nouvelles observations
 *   3. Calcul des ImpactScores pour tous les spots côtiers
 */
#[AsMessageHandler]
final class IngestionScheduleHandler
{
    // Zone d'ingestion : archipel guadeloupéen (Grande-Terre, Basse-Terre,
    // Marie-Galante, Les Saintes, La Désirade) + ~350 km d'océan à l'est
    // pour détecter les sargasses en approche bien avant qu'elles touchent terre.
    private const ZONES = [
        'guadeloupe' => [-62.50, 15.70, -58.50, 17.00],
    ];

    public function __construct(
        private IngestionService       $ingestion,
        private DriftSimulationService $drift,
        private ImpactScoreService     $scores,
        private EntityManagerInterface $em,
        private LoggerInterface        $logger,
        #[Autowire('%kernel.project_dir%')] private string $projectDir,
    ) {}

    public function __invoke(IngestionScheduleMessage $message): void
    {
        $date = new \DateTimeImmutable('yesterday');
        $this->logger->info('Scheduled ingestion started', ['date' => $date->format('Y-m-d')]);

        // Étape 1 : ingestion de toutes les zones
        $succeeded = 0;
        $failed    = 0;
        foreach (self::ZONES as $name => $bbox) {
            try {
                $this->ingestion->ingestWithFallback($bbox, $date);
                $this->logger->info('Zone ingested', ['zone' => $name]);
                ++$succeeded;
            } catch (\Throwable $e) {
                $this->logger->error('Ingestion failed', ['zone' => $name, 'error' => $e->getMessage()]);
                ++$failed;
            }
        }

        if ($succeeded === 0) {
            $this->logger->critical('All zones failed — no data ingested this cycle', [
                'date'  => $date->format('Y-m-d'),
                'zones' => array_keys(self::ZONES),
                'count' => $failed,
            ]);
        } else {
            $this->logger->info('Ingestion cycle summary', [
                'succeeded' => $succeeded,
                'failed'    => $failed,
                'date'      => $date->format('Y-m-d'),
            ]);
        }

        // Étape 2 : forecasts pour les observations sans prévision
        $observations = $this->em->getRepository(SargassumObservation::class)
            ->createQueryBuilder('o')
            ->leftJoin('o.forecasts', 'f')
            ->where('f.id IS NULL')
            ->orderBy('o.detectedAt', 'DESC')
            ->setMaxResults(10)
            ->getQuery()
            ->getResult();

        foreach ($observations as $observation) {
            try {
                $forecasts = $this->drift->computeForecasts($observation);
                $this->scores->computeForObservation($observation, $forecasts);
                $this->logger->info('Forecasts computed', ['observation' => (string) $observation->getId()]);
            } catch (\Throwable $e) {
                $this->logger->error('Forecast failed', [
                    'observation' => (string) $observation->getId(),
                    'error'       => $e->getMessage(),
                ]);
            }
        }

        $this->logger->info('Scheduled ingestion completed');

        // Étape 4 : régénération des vector tiles depuis les données fraîches
        $this->regenerateTiles();
    }

    private function regenerateTiles(): void
    {
        $process = new Process(
            ['php', 'bin/console', 'app:generate-tiles', '--env=prod', '--no-debug'],
            $this->projectDir
        );
        $process->setTimeout(300);
        $process->run();

        if ($process->isSuccessful()) {
            $this->logger->info('Vector tiles regenerated');
        } else {
            $this->logger->error('Tile generation failed', ['output' => $process->getErrorOutput()]);
        }
    }
}
