"""Reverse geocoding usando Nominatim (OpenStreetMap).""" import json import urllib.request import urllib.parse def nominatim_reverse_geocode(lat: float, lon: float, lang: str = "es") -> dict: """Convierte coordenadas lat/lon a una dirección estructurada usando Nominatim. Args: lat: Latitud en grados decimales. lon: Longitud en grados decimales. lang: Código de idioma para la respuesta (ISO 639-1). Por defecto "es". Returns: Diccionario con campos normalizados de la dirección. Raises: RuntimeError: Si la petición HTTP falla o el servidor retorna error. """ params = urllib.parse.urlencode({ "format": "jsonv2", "lat": str(lat), "lon": str(lon), "accept-language": lang, "zoom": "18", }) url = f"https://nominatim.openstreetmap.org/reverse?{params}" req = urllib.request.Request( url, headers={"User-Agent": "fn_registry/1.0"}, ) try: with urllib.request.urlopen(req, timeout=5) as resp: if resp.status != 200: raise RuntimeError( f"nominatim_reverse_geocode: HTTP {resp.status} para lat={lat}, lon={lon}" ) data = json.loads(resp.read().decode("utf-8")) except urllib.error.HTTPError as e: raise RuntimeError( f"nominatim_reverse_geocode: HTTP {e.code} para lat={lat}, lon={lon}" ) from e except urllib.error.URLError as e: raise RuntimeError( f"nominatim_reverse_geocode: error de red — {e.reason}" ) from e address = data.get("address", {}) city = ( address.get("city") or address.get("town") or address.get("village") or "" ) return { "display_name": data.get("display_name", ""), "street": address.get("road", ""), "house_number": address.get("house_number", ""), "neighbourhood": address.get("neighbourhood", ""), "city": city, "state": address.get("state", ""), "country": address.get("country", ""), "postcode": address.get("postcode", ""), "lat": float(data.get("lat", lat)), "lon": float(data.get("lon", lon)), "osm_type": data.get("osm_type", ""), "osm_id": int(data.get("osm_id", 0)), }