"""Fetch OSM points of interest around Westerville via the Overpass API.

Loads a curated set of amenity/leisure/shop tags into `osm_pois` with a
canonical `category` field for map filtering.
"""
from __future__ import annotations

import json
from pathlib import Path

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

DATA_DIR = Path("/home/m3ac/genoa-entwuerfe.com")
CENTER_LAT = 40.14917
CENTER_LNG = -82.899
RADIUS_M   = 8000      # 8 km around Whitetail (larger balloons timeout)
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",
]

# tag → category label
CATS = {
    "restaurant": "restaurants",
    "fast_food":  "restaurants",
    "cafe":       "cafes",
    "pub":        "bars",
    "bar":        "bars",
    "school":     "schools",
    "kindergarten": "schools",
    "college":    "schools",
    "university": "schools",
    "library":    "civic",
    "townhall":   "civic",
    "post_office": "civic",
    "police":     "civic",
    "fire_station":"civic",
    "place_of_worship": "worship",
    "hospital":   "medical",
    "clinic":     "medical",
    "pharmacy":   "medical",
    "dentist":    "medical",
    "doctors":    "medical",
    "fuel":       "fuel",
    "bank":       "bank",
    "atm":        "bank",
    "supermarket":"grocery",
    "convenience":"grocery",
    "park":       "parks",
    "playground": "parks",
    "sports_centre":"parks",
    "swimming_pool":"parks",
    "polling_place":"civic",
}


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 _q():
    return f"""
    [out:json][timeout:60];
    (
      node["amenity"](around:{RADIUS_M},{CENTER_LAT},{CENTER_LNG});
      node["leisure"](around:{RADIUS_M},{CENTER_LAT},{CENTER_LNG});
      node["shop"~"supermarket|convenience"](around:{RADIUS_M},{CENTER_LAT},{CENTER_LNG});
    );
    out center tags;
    """


def main():
    print(f"[overpass] {RADIUS_M/1000:.0f} km around {CENTER_LAT},{CENTER_LNG}")
    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(_q())}"
    els = None
    for url in OVERPASS_MIRRORS:
        try:
            print(f"  trying {url}")
            r = requests.post(url, data=body, headers=headers, timeout=180)
            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)} raw nodes")
    rows = []
    for el in els:
        tags = el.get("tags") or {}
        key = tags.get("amenity") or tags.get("leisure") or tags.get("shop") or ""
        cat = CATS.get(key)
        if not cat: continue
        rows.append({
            "osm_id":   el["id"],
            "name":     tags.get("name") or key,
            "category": cat,
            "amenity":  key,
            "tags":     json.dumps(tags),
            "lat":      el["lat"],
            "lng":      el["lon"],
        })
    print(f"[filter] {len(rows)} categorized POIs")
    if not rows: return
    gdf = gpd.GeoDataFrame(rows,
        geometry=[Point(r["lng"], r["lat"]) for r in rows], crs="EPSG:4326")
    engine = create_engine(
        f"postgresql+psycopg2://gisapp:{_env('GISPASS')}@127.0.0.1:5432/westerville"
    )
    gdf.to_postgis("osm_pois", engine, if_exists="replace", index=False)
    with engine.begin() as conn:
        conn.execute(text("CREATE INDEX osm_pois_geom_idx ON osm_pois USING GIST (geometry);"))
        conn.execute(text("CREATE INDEX osm_pois_cat_idx  ON osm_pois (category);"))
        (n,) = conn.execute(text("SELECT count(*) FROM osm_pois")).one()
    print(f"[postgis] osm_pois: {n} rows")


if __name__ == "__main__":
    main()
