"""Tests para generate_isochrones_by_zone_pipeline.

Crea archivos GeoJSON temporales con zonas sintéticas sobre Madrid
y verifica el resultado del pipeline con el stack Valhalla activo.
"""

from __future__ import annotations

import asyncio
import json
import os
import sys
import tempfile

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))

from python.functions.pipelines.generate_isochrones_by_zone_pipeline import (
    generate_isochrones_by_zone_pipeline,
)


def _make_square_geojson(center_lon: float, center_lat: float, half: float) -> dict:
    """Crea un GeoJSON Polygon cuadrado alrededor de (center_lon, center_lat)."""
    lo, hi_lon = center_lon - half, center_lon + half
    la, hi_lat = center_lat - half, center_lat + half
    return {
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [
                        [
                            [lo, la],
                            [hi_lon, la],
                            [hi_lon, hi_lat],
                            [lo, hi_lat],
                            [lo, la],
                        ]
                    ],
                },
                "properties": {},
            }
        ],
    }


def test_generate_isochrones_by_zone_pipeline():
    """Dos zonas cuadradas sintéticas, 50 puntos con seconds=600, 3 centros en Madrid."""
    with tempfile.TemporaryDirectory() as tmpdir:
        # Zona norte: cuadrado alrededor de Chamartín (Madrid norte)
        zone_norte_path = os.path.join(tmpdir, "zone_norte.geojson")
        with open(zone_norte_path, "w") as f:
            json.dump(_make_square_geojson(-3.685, 40.47, 0.05), f)

        # Zona sur: cuadrado alrededor de Vallecas (Madrid sur)
        zone_sur_path = os.path.join(tmpdir, "zone_sur.geojson")
        with open(zone_sur_path, "w") as f:
            json.dump(_make_square_geojson(-3.666, 40.38, 0.05), f)

        zones = [
            {"label": "Norte", "geojson_path": zone_norte_path, "exclude_geojson_path": None},
            {"label": "Sur", "geojson_path": zone_sur_path, "exclude_geojson_path": None},
        ]

        # 50 puntos: 25 en zona norte, 25 en zona sur, todos con seconds=600 (10 min)
        points_norte = [
            {"lat": 40.47 + i * 0.001, "lon": -3.685 + i * 0.001, "seconds": 600.0}
            for i in range(-12, 13)
        ]
        points_sur = [
            {"lat": 40.38 + i * 0.001, "lon": -3.666 + i * 0.001, "seconds": 600.0}
            for i in range(-12, 13)
        ]
        points = points_norte + points_sur

        # 3 centros: 2 en norte, 1 en sur
        centers = [
            {"lat": 40.47, "lon": -3.685, "id": "centro_norte_a"},
            {"lat": 40.465, "lon": -3.680, "id": "centro_norte_b"},
            {"lat": 40.380, "lon": -3.666, "id": "centro_sur_a"},
        ]

        result = asyncio.run(
            generate_isochrones_by_zone_pipeline(
                zones=zones,
                points=points,
                centers=centers,
                base_url="http://localhost:8002",
                concurrency=4,
            )
        )

    assert isinstance(result, dict)
    assert "zones" in result
    zone_results = result["zones"]

    assert len(zone_results) == 2, f"Esperadas 2 zonas, got {len(zone_results)}"

    for z in zone_results:
        assert "label" in z
        assert "minutes" in z
        assert "n_points" in z
        assert "n_centers" in z
        assert "isochrones" in z
        assert isinstance(z["isochrones"], list)

    # p75 de 600s = 10 min → minutes ≈ 10
    for z in zone_results:
        if z["n_points"] > 0:
            assert z["minutes"] is not None
            assert 9.5 <= z["minutes"] <= 10.5, f"p75 esperado ~10 min, got {z['minutes']}"

    # Al menos una zona debe tener isócronas (Valhalla activo)
    total_isos = sum(len(z["isochrones"]) for z in zone_results)
    assert total_isos >= 1, "Al menos una isócrona debe generarse"
