<?php

namespace App\Command;

use App\Entity\CoastalPoint;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Contracts\HttpClient\HttpClientInterface;

#[AsCommand(
    name: 'app:import-coastal-points',
    description: 'Importe les plages/ports/spots depuis OpenStreetMap (1 seule requête Overpass) — idempotent',
)]
class ImportCoastalPointsCommand extends Command
{
    private const OVERPASS_URL = 'https://overpass-api.de/api/interpreter';

    /**
     * Bboxes par île : [sud, ouest, nord, est]
     * Utilisées pour :
     *   1. construire les statements Overpass (1 requête globale)
     *   2. déterminer la région d'un point en PHP
     */
    private const ISLANDS = [
        'Basse-Terre'      => ['bbox' => [15.82, -61.82, 16.52, -61.55], 'region' => 'Guadeloupe'],
        'Grande-Terre'     => ['bbox' => [15.97, -61.55, 16.52, -61.07], 'region' => 'Guadeloupe'],
        'Marie-Galante'    => ['bbox' => [15.83, -61.40, 16.08, -61.10], 'region' => 'Guadeloupe'],
        'La Désirade'      => ['bbox' => [16.27, -61.10, 16.37, -60.82], 'region' => 'Guadeloupe'],
        'Les Saintes'      => ['bbox' => [15.83, -61.68, 15.90, -61.55], 'region' => 'Guadeloupe'],
        'Martinique'       => ['bbox' => [14.38, -61.25, 14.88, -60.80], 'region' => 'Martinique'],
        'Sainte-Lucie'     => ['bbox' => [13.70, -61.10, 14.15, -60.85], 'region' => 'Sainte-Lucie'],
        'Barbade'          => ['bbox' => [13.00, -59.80, 13.40, -59.40], 'region' => 'Barbade'],
        'Saint-Martin'     => ['bbox' => [17.85, -63.20, 18.18, -62.95], 'region' => 'Saint-Martin'],
        'Saint-Barthélemy' => ['bbox' => [17.85, -62.90, 17.98, -62.78], 'region' => 'Saint-Barthélemy'],
        'Dominique'        => ['bbox' => [15.20, -61.50, 15.65, -61.24], 'region' => 'Dominique'],
    ];

    public function __construct(
        private EntityManagerInterface $em,
        private HttpClientInterface $httpClient,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Affiche sans persister en base');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io     = new SymfonyStyle($input, $output);
        $dryRun = (bool) $input->getOption('dry-run');

        $io->title('Import OpenStreetMap — Points côtiers Antilles');
        if ($dryRun) {
            $io->note('Mode dry-run : aucune écriture en base');
        }

        $io->text('Envoi d\'une seule requête Overpass pour toutes les îles…');
        $elements = $this->queryOverpass($io);

        if (empty($elements)) {
            $io->warning('Aucun résultat Overpass.');
            return Command::FAILURE;
        }

        $io->text(sprintf('%d éléments OSM reçus, attribution des régions…', count($elements)));

        $repo    = $this->em->getRepository(CoastalPoint::class);
        $created = 0;
        $skipped = 0;

        foreach ($elements as $el) {
            $osmId   = $el['type'] . '/' . $el['id'];
            $osmName = $el['tags']['name'] ?? $el['tags']['name:fr'] ?? null;
            if ($osmName === null) {
                continue;
            }

            $lat = $el['lat'] ?? ($el['center']['lat'] ?? null);
            $lon = $el['lon'] ?? ($el['center']['lon'] ?? null);
            if ($lat === null || $lon === null) {
                continue;
            }

            $region = $this->detectRegion((float) $lat, (float) $lon);
            if ($region === null) {
                continue; // hors de nos zones d'intérêt
            }

            if ($repo->findOneBy(['osmId' => $osmId]) !== null) {
                ++$skipped;
                continue;
            }
            if ($repo->findOneBy(['name' => $osmName, 'region' => $region]) !== null) {
                ++$skipped;
                continue;
            }

            $type = $this->mapType($el['tags']);
            $io->writeln(sprintf('  + %-45s [%-8s] %s', $osmName, $type, $region));

            if (!$dryRun) {
                $point = new CoastalPoint();
                $point->setName($osmName);
                $point->setGeometry(sprintf('SRID=4326;POINT(%f %f)', $lon, $lat));
                $point->setType($type);
                $point->setRegion($region);
                $point->setOsmId($osmId);
                $this->em->persist($point);
            }

            ++$created;
        }

        if (!$dryRun) {
            $this->em->flush();
        }

        $verb = $dryRun ? 'trouvé(s)' : 'créé(s)';
        $io->success(sprintf('%d point(s) %s, %d ignoré(s) (déjà existants).', $created, $verb, $skipped));

        return Command::SUCCESS;
    }

    /**
     * Une seule requête Overpass avec toutes les bboxes en union.
     *
     * @return array<int, array<string, mixed>>
     */
    private function queryOverpass(SymfonyStyle $io): array
    {
        $statements = '';
        foreach (self::ISLANDS as $config) {
            [$s, $w, $n, $e] = $config['bbox'];
            $bbox = "{$s},{$w},{$n},{$e}";

            $statements .= "  node[\"natural\"=\"beach\"][\"name\"]({$bbox});\n";
            $statements .= "  node[\"natural\"=\"beach\"][\"name:fr\"]({$bbox});\n";
            $statements .= "  node[\"leisure\"=\"beach_resort\"][\"name\"]({$bbox});\n";
            $statements .= "  node[\"leisure\"=\"marina\"][\"name\"]({$bbox});\n";
            $statements .= "  node[\"harbour\"][\"name\"]({$bbox});\n";
            $statements .= "  node[\"amenity\"=\"ferry_terminal\"][\"name\"]({$bbox});\n";
            $statements .= "  node[\"sport\"=\"surfing\"][\"name\"]({$bbox});\n";
            $statements .= "  way[\"natural\"=\"beach\"][\"name\"]({$bbox});\n";
            $statements .= "  way[\"natural\"=\"beach\"][\"name:fr\"]({$bbox});\n";
            $statements .= "  way[\"leisure\"=\"marina\"][\"name\"]({$bbox});\n";
            $statements .= "  way[\"harbour\"][\"name\"]({$bbox});\n";
            $statements .= "  relation[\"natural\"=\"beach\"][\"name\"]({$bbox});\n";
        }

        $query = "[out:json][timeout:60];\n(\n{$statements});\nout center;";

        try {
            $response = $this->httpClient->request('POST', self::OVERPASS_URL, [
                'body'    => ['data' => $query],
                'timeout' => 65,
            ]);

            $data = $response->toArray();
            return $data['elements'] ?? [];
        } catch (\Throwable $e) {
            $io->error('Overpass error : ' . $e->getMessage());
            return [];
        }
    }

    /**
     * Détermine la région d'un point par appartenance à une bbox.
     * En cas de recouvrement, prend la première bbox correspondante.
     */
    private function detectRegion(float $lat, float $lon): ?string
    {
        foreach (self::ISLANDS as $config) {
            [$s, $w, $n, $e] = $config['bbox'];
            if ($lat >= $s && $lat <= $n && $lon >= $w && $lon <= $e) {
                return $config['region'];
            }
        }
        return null;
    }

    /** @param array<string, string> $tags */
    private function mapType(array $tags): string
    {
        if (($tags['sport']   ?? '') === 'surfing')        return 'surf';
        if (($tags['harbour'] ?? '') === 'fishing')        return 'fishing';
        if (($tags['amenity'] ?? '') === 'ferry_terminal') return 'port';
        if (($tags['leisure'] ?? '') === 'marina')         return 'port';
        return 'beach';
    }
}
