"""Pipeline: cuenta cuántos puntos caen dentro de cada zona geográfica GeoJSON."""

from __future__ import annotations

import sys
import os

_FUNCTIONS_DIR = os.path.join(os.path.dirname(__file__), "..")
if _FUNCTIONS_DIR not in sys.path:
    sys.path.insert(0, _FUNCTIONS_DIR)

from geo.load_geojson_polygons import load_geojson_polygons
from geo.polygon_bbox import polygon_bbox
from geo.point_in_polygons_bbox import point_in_polygons_bbox


def count_points_per_zone_pipeline(
    points: list[tuple[float, float]],
    zones: list[dict],
) -> dict:
    """Cuenta cuántos puntos caen dentro de cada zona geográfica.

    Para cada zona carga los polígonos GeoJSON, precalcula los bboxes
    y aplica prefiltraje+ray-casting para contar puntos dentro.
    Un mismo punto puede contarse en varias zonas si los polígonos se solapan.

    Args:
        points: Lista de (lon, lat) de los puntos a clasificar.
        zones: Lista de dicts con:
               - "label" (str): nombre de la zona.
               - "geojson_path" (str): ruta al GeoJSON de la zona.

    Returns:
        Dict con claves:
          "counts"         (dict[str, int]): {label: n_puntos_en_zona}.
          "total_points"   (int): total de puntos de entrada.
          "total_assigned" (int): suma de conteos (puede superar total_points si hay solapamiento).
          "unassigned"     (int): puntos que no caen en ninguna zona.
    """
    counts: dict[str, int] = {}
    # Track which points were assigned to at least one zone
    assigned_flags = [False] * len(points)

    for zone in zones:
        label = zone["label"]
        polygons = load_geojson_polygons(zone["geojson_path"])
        bboxes = [polygon_bbox(p) for p in polygons]

        zone_count = 0
        for idx, (lon, lat) in enumerate(points):
            if point_in_polygons_bbox(float(lon), float(lat), polygons, bboxes):
                zone_count += 1
                assigned_flags[idx] = True

        counts[label] = zone_count

    total_points = len(points)
    total_assigned = sum(counts.values())
    unassigned = sum(1 for f in assigned_flags if not f)

    return {
        "counts": counts,
        "total_points": total_points,
        "total_assigned": total_assigned,
        "unassigned": unassigned,
    }
