"""Tests para count_points_per_zone_pipeline.

Usa un cuadrado sintético como zona y puntos aleatorios entre lat[40,41] lon[-4,-3].
"""

from __future__ import annotations

import json
import os
import random
import sys
import tempfile

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

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


def _make_square_geojson(min_lon: float, min_lat: float, max_lon: float, max_lat: float) -> dict:
    """Crea un GeoJSON Polygon cuadrado con las coordenadas dadas."""
    return {
        "type": "FeatureCollection",
        "features": [
            {
                "type": "Feature",
                "geometry": {
                    "type": "Polygon",
                    "coordinates": [
                        [
                            [min_lon, min_lat],
                            [max_lon, min_lat],
                            [max_lon, max_lat],
                            [min_lon, max_lat],
                            [min_lon, min_lat],
                        ]
                    ],
                },
                "properties": {},
            }
        ],
    }


def test_count_points_per_zone_pipeline():
    """100 puntos aleatorios en [40,41]x[-4,-3]. Zona = cuadrado interior [40.2,40.8]x[-3.8,-3.2]."""
    random.seed(42)
    # Puntos (lon, lat) — orden GeoJSON
    points = [
        (random.uniform(-4.0, -3.0), random.uniform(40.0, 41.0))
        for _ in range(100)
    ]

    # Zona interior: cuadrado centrado que cubre ~36% del área total → espera ~36 puntos
    zone_min_lon, zone_max_lon = -3.8, -3.2
    zone_min_lat, zone_max_lat = 40.2, 40.8

    # Cuántos puntos deben caer (referencia para assert)
    expected_inside = sum(
        1 for lon, lat in points
        if zone_min_lon <= lon <= zone_max_lon and zone_min_lat <= lat <= zone_max_lat
    )

    with tempfile.TemporaryDirectory() as tmpdir:
        zone_path = os.path.join(tmpdir, "zone_centro.geojson")
        with open(zone_path, "w") as f:
            json.dump(
                _make_square_geojson(zone_min_lon, zone_min_lat, zone_max_lon, zone_max_lat),
                f,
            )

        zones = [{"label": "Centro", "geojson_path": zone_path}]

        result = count_points_per_zone_pipeline(points=points, zones=zones)

    assert isinstance(result, dict)
    assert set(result.keys()) == {"counts", "total_points", "total_assigned", "unassigned"}

    assert result["total_points"] == 100
    assert result["counts"]["Centro"] > 0, "Debe haber puntos en la zona"
    assert result["counts"]["Centro"] == expected_inside, (
        f"Esperados {expected_inside} puntos, got {result['counts']['Centro']}"
    )
    assert result["total_assigned"] == expected_inside
    assert result["unassigned"] == 100 - expected_inside
