"""Fetch OSM roads + trails within ~10 km of Westerville via Overpass.

Loads LineStrings into `osm_roads` with a normalized `road_class` field.
"""
from __future__ import annotations

import json
from pathlib import Path

import geopandas as gpd
import requests
from shapely.geometry import LineString
from sqlalchemy import create_engine, text

DATA_DIR = Path("/home/m3ac/genoa-entwuerfe.com")
CENTER_LAT = 40.14917
CENTER_LNG = -82.899
RADIUS_M   = 10000
OVERPASS_MIRRORS = [
    "https://overpass-api.de/api/interpreter",
    "https://lz4.overpass-api.de/api/interpreter",
    "https://z.overpass-api.de/api/interpreter",
    "https://overpass.kumi.systems/api/interpreter",
]

CLASS_OF = {
    "motorway": "motorway", "motorway_link": "motorway",
    "trunk": "trunk", "trunk_link": "trunk",
    "primary": "primary", "primary_link": "primary",
    "secondary": "secondary", "secondary_link": "secondary",
    "tertiary": "tertiary", "tertiary_link": "tertiary",
    "residential": "residential", "unclassified": "residential", "living_street": "residential",
    "service": "service",
    "cycleway": "cycleway",
    "footway": "footway", "path": "footway", "pedestrian": "footway",
    "track": "track", "bridleway": "track",
}


def _env(k):
    for line in (DATA_DIR / ".env.gis").read_text().splitlines():
        if line.startswith(f"{k}="):
            return line.split("=", 1)[1].strip()
    raise SystemExit(f"{k} missing")


def _query() -> str:
    kinds = "|".join(CLASS_OF.keys())
    return f"""
    [out:json][timeout:90];
    (
      way["highway"~"^({kinds})$"](around:{RADIUS_M},{CENTER_LAT},{CENTER_LNG});
    );
    out geom tags;
    """


def main():
    headers = {
        "User-Agent": "westerville-map/1.0 (contact: mholleran43@gmail.com)",
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded",
    }
    body = f"data={requests.utils.quote(_query())}"
    els = None
    for url in OVERPASS_MIRRORS:
        try:
            print(f"[overpass] {url}")
            r = requests.post(url, data=body, headers=headers, timeout=240)
            r.raise_for_status()
            els = r.json().get("elements", [])
            break
        except (requests.HTTPError, requests.Timeout, requests.ConnectionError) as e:
            print(f"  failed: {e.__class__.__name__} {getattr(e.response,'status_code','')}")
    if els is None:
        raise SystemExit("all overpass mirrors failed")
    print(f"[overpass] {len(els)} way objects")

    rows = []
    for w in els:
        tags = w.get("tags") or {}
        highway = tags.get("highway")
        rc = CLASS_OF.get(highway)
        if not rc: continue
        pts = w.get("geometry") or []
        if len(pts) < 2: continue
        try:
            geom = LineString([(p["lon"], p["lat"]) for p in pts])
        except Exception:
            continue
        rows.append({
            "osm_id":     w["id"],
            "name":       tags.get("name") or "",
            "highway":    highway,
            "road_class": rc,
            "surface":    tags.get("surface"),
            "maxspeed":   tags.get("maxspeed"),
            "oneway":     tags.get("oneway"),
            "geometry":   geom,
        })
    print(f"[roads] {len(rows)} styled segments")
    if not rows: return
    gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")
    engine = create_engine(
        f"postgresql+psycopg2://gisapp:{_env('GISPASS')}@127.0.0.1:5432/westerville"
    )
    gdf.to_postgis("osm_roads", engine, if_exists="replace", index=False)
    with engine.begin() as conn:
        conn.execute(text("CREATE INDEX osm_roads_geom_idx  ON osm_roads USING GIST (geometry);"))
        conn.execute(text("CREATE INDEX osm_roads_class_idx ON osm_roads (road_class);"))
        (n,) = conn.execute(text("SELECT count(*) FROM osm_roads")).one()
    print(f"[postgis] osm_roads: {n} rows")


if __name__ == "__main__":
    main()
