"""US Census Geocoder - address -> lat/lng/county/state.

API gratis, no key, sin rate limits documentados (uso razonable).
Documentacion: https://geocoding.geo.census.gov/geocoder/Geocoding_Services_API.pdf

Limitacion: SOLO USA (incluye PR, GU, AS, MP, VI).

Devuelve dict con:
    matched_address, lat, lng, city, state, zip, county_name, county_fips, state_fips
"""

from __future__ import annotations

import requests

from .base import FetcherError, USER_AGENT, DEFAULT_TIMEOUT


CENSUS_URL = "https://geocoding.geo.census.gov/geocoder/geographies/onelineaddress"


def fetch_geocode(address: str) -> dict:
    """Geocodifica una direccion USA. Raises FetcherError si no hay match."""
    if not address or len(address.strip()) < 5:
        raise FetcherError("address vacio o muy corto")

    params = {
        "address": address.strip(),
        "benchmark": "Public_AR_Current",
        "vintage": "Current_Current",
        "format": "json",
        # Necesitamos Census Tracts ademas de Counties para neighborhood_class
        "layers": "Census Tracts,Counties,2020 Census Blocks",
    }
    headers = {"User-Agent": USER_AGENT}

    try:
        r = requests.get(CENSUS_URL, params=params, headers=headers, timeout=DEFAULT_TIMEOUT)
        r.raise_for_status()
    except requests.RequestException as e:
        raise FetcherError(f"HTTP error: {e}") from e

    try:
        data = r.json()
    except ValueError as e:
        raise FetcherError(f"JSON parse error: {e}") from e

    matches = data.get("result", {}).get("addressMatches", [])
    if not matches:
        raise FetcherError(f"No geocode match for: {address!r}")

    m = matches[0]
    coords = m.get("coordinates", {}) or {}
    comp = m.get("addressComponents", {}) or {}
    geos = m.get("geographies", {}) or {}

    # Counties layer; nombre varia entre vintages: a veces "Counties", a veces con sufijo
    counties = (
        geos.get("Counties")
        or geos.get("2020 Census Counties")
        or geos.get("County Subdivisions")
        or []
    )
    county = counties[0] if counties else {}

    # Census Tracts: granularidad de vecindario (~4K personas por tract)
    tracts = geos.get("Census Tracts") or geos.get("2020 Census Tracts") or []
    tract = tracts[0] if tracts else {}

    return {
        "matched_address": m.get("matchedAddress"),
        "lat": coords.get("y"),
        "lng": coords.get("x"),
        "city": comp.get("city"),
        "state": comp.get("state"),
        "zip": comp.get("zip"),
        "county_name": county.get("NAME") or county.get("BASENAME"),
        "county_fips": county.get("GEOID"),     # e.g. "12086"
        "state_fips": county.get("STATE"),       # e.g. "12"
        # NEW: tract info para neighborhood_class
        "tract_geoid": tract.get("GEOID"),       # e.g. "12086007608"
        "tract_code": tract.get("TRACT"),        # e.g. "007608" (6-digit, sin state/county)
        "tract_name": tract.get("NAME"),         # e.g. "Census Tract 76.08"
        "county_code_only": county.get("COUNTY") or tract.get("COUNTY"),  # e.g. "086" (3-digit county solo)
    }
