"""Isócronas de múltiples puntos en paralelo via Valhalla (async)."""

from __future__ import annotations

import asyncio

import httpx


async def valhalla_isochrones_async(
    requests: list[dict],
    base_url: str = "http://localhost:8002",
    costing: str = "auto",
    concurrency: int = 6,
    timeout_s: float = 120.0,
    denoise: float = 0.6,
    generalize_m: int = 50,
) -> list[dict | None]:
    """Calcula isócronas para múltiples puntos en paralelo usando Valhalla.

    Args:
        requests: Lista de dicts con 'lat' (float), 'lon' (float), 'minutes' (int)
                  y opcionalmente 'id' (str). Cada elemento genera una isócrona.
        base_url: URL base del servidor Valhalla.
        costing: Modelo de coste ('auto', 'bicycle', 'pedestrian', etc.).
        concurrency: Número máximo de requests simultáneas.
        timeout_s: Timeout en segundos por request.
        denoise: Factor de suavizado del contorno (0-1).
        generalize_m: Tolerancia de generalización en metros.

    Returns:
        Lista paralela a 'requests' con GeoJSON dict o None por cada punto.
        Preserva el orden de entrada.
    """
    url = f"{base_url.rstrip('/')}/isochrone"
    sem = asyncio.Semaphore(concurrency)
    timeout = httpx.Timeout(timeout_s)

    async def _fetch_one(
        client: httpx.AsyncClient,
        req: dict,
    ) -> dict | None:
        payload = {
            "locations": [{"lat": float(req["lat"]), "lon": float(req["lon"])}],
            "costing": costing,
            "contours": [{"time": int(req["minutes"])}],
            "polygons": True,
            "denoise": denoise,
            "generalize": generalize_m,
            "format": "geojson",
        }
        try:
            async with sem:
                r = await client.post(url, json=payload)
                r.raise_for_status()
                return r.json()
        except Exception:
            return None

    async with httpx.AsyncClient(timeout=timeout) as client:
        tasks = [_fetch_one(client, req) for req in requests]
        return list(await asyncio.gather(*tasks))
