"""Fetch POIs from OSM Overpass for all sites in one bulk query.

POI taxonomy (matches the user's spec):
  EDUCATION
    kindergarten   amenity=kindergarten
    school         amenity=school
    university     amenity=university | college
  HEALTH
    pharmacy       amenity=pharmacy
    clinic         amenity=clinic | doctors
    hospital       amenity=hospital
  RETAIL
    shop_big       shop=mall | supermarket | department_store | hypermarket
    shop_med       shop=convenience | grocery | bakery
    shop_small     shop=kiosk | newsagent
  TRANSIT
    bus_stop       highway=bus_stop | public_transport=platform
    tram_stop      railway=tram_stop
    metro          railway=station + station=subway
  LEISURE
    park           leisure=park | garden
    playground     leisure=playground
    sports         leisure=sports_centre | fitness_centre | pitch
"""
import sqlite3, pathlib, requests, time, json, math, urllib3
urllib3.disable_warnings()

DB = pathlib.Path(__file__).parent / "analysis.db"
CACHE = pathlib.Path(__file__).parent / "cache" / "overpass_raw.json"

OVERPASS_ENDPOINTS = [
    "https://overpass-api.de/api/interpreter",
    "https://overpass.kumi.systems/api/interpreter",
    "https://overpass.openstreetmap.ru/api/interpreter",
]

# (category, overpass filter)
QUERIES = [
    ("kindergarten",  '["amenity"="kindergarten"]'),
    ("school",        '["amenity"="school"]'),
    ("university",    '["amenity"~"^(university|college)$"]'),
    ("pharmacy",      '["amenity"="pharmacy"]'),
    ("clinic",        '["amenity"~"^(clinic|doctors)$"]'),
    ("hospital",      '["amenity"="hospital"]'),
    ("shop_big",      '["shop"~"^(mall|supermarket|department_store|hypermarket)$"]'),
    ("shop_med",      '["shop"~"^(convenience|grocery|bakery)$"]'),
    ("shop_small",    '["shop"~"^(kiosk|newsagent)$"]'),
    ("bus_stop",      '["highway"="bus_stop"]'),
    ("tram_stop",     '["railway"="tram_stop"]'),
    ("metro",         '["station"="subway"]'),
    ("park",          '["leisure"~"^(park|garden)$"]'),
    ("playground",    '["leisure"="playground"]'),
    ("sports",        '["leisure"~"^(sports_centre|fitness_centre|pitch)$"]'),
]

def haversine_m(lat1, lon1, lat2, lon2):
    R = 6371000
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp = math.radians(lat2-lat1); dl = math.radians(lon2-lon1)
    a = math.sin(dp/2)**2 + math.cos(p1)*math.cos(p2)*math.sin(dl/2)**2
    return 2 * R * math.asin(math.sqrt(a))

def bbox(rows, pad_deg=0.05):
    lats=[r[0] for r in rows]; lons=[r[1] for r in rows]
    return (min(lats)-pad_deg, min(lons)-pad_deg, max(lats)+pad_deg, max(lons)+pad_deg)

def overpass_query(filt, b):
    q = f"""
[out:json][timeout:120];
(
  node{filt}({b[0]},{b[1]},{b[2]},{b[3]});
  way{filt}({b[0]},{b[1]},{b[2]},{b[3]});
);
out center tags;
"""
    last_err = None
    for ep in OVERPASS_ENDPOINTS:
        try:
            r = requests.post(ep, data={"data": q}, timeout=180, verify=False,
                              headers={"User-Agent":"gendesign-research/1.0"})
            if r.status_code == 200:
                return r.json()
            last_err = f"HTTP {r.status_code} from {ep}"
            time.sleep(2)
        except Exception as e:
            last_err = f"{ep}: {e}"
            time.sleep(2)
    raise RuntimeError(f"All Overpass endpoints failed: {last_err}")

def main():
    conn = sqlite3.connect(DB)
    sites = conn.execute("SELECT site_id, lat, lon FROM sites").fetchall()
    print(f"Sites: {len(sites)}")
    coords = [(s[1], s[2]) for s in sites]
    b = bbox(coords)
    print(f"BBox (S,W,N,E): {b}")

    cache_data = {}
    for cat, filt in QUERIES:
        print(f"  fetching {cat:<14} ...", end=" ", flush=True)
        d = overpass_query(filt, b)
        elements = d.get("elements", [])
        cache_data[cat] = elements
        print(f"{len(elements)} elements")
        time.sleep(2)  # be kind

    CACHE.parent.mkdir(parents=True, exist_ok=True)
    with open(CACHE, 'w') as f: json.dump(cache_data, f, ensure_ascii=False)
    print(f"\nCache: {CACHE} ({CACHE.stat().st_size/1024:.0f} KB)")

    # Compute nearest POI per site per category, plus all POIs within 1km
    conn.execute("DELETE FROM pois")
    n_pois = 0
    for cat, elems in cache_data.items():
        # extract (lat,lon,name,raw)
        poi_list = []
        for el in elems:
            if el["type"] == "node":
                lat, lon = el.get("lat"), el.get("lon")
            else:
                c = el.get("center") or {}
                lat, lon = c.get("lat"), c.get("lon")
            if lat is None or lon is None: continue
            tags = el.get("tags") or {}
            name = tags.get("name") or tags.get("operator") or ""
            poi_list.append((lat, lon, name, el["type"], el["id"], json.dumps(tags, ensure_ascii=False)))
        # for each site, find within 2 km (we'll bucket by distance later)
        for s in sites:
            site_id, slat, slon = s
            for plat, plon, pname, ptype, pid, ptags in poi_list:
                d = haversine_m(slat, slon, plat, plon)
                if d <= 2000:
                    conn.execute("""INSERT INTO pois(site_id,category,osm_type,osm_id,name,lat,lon,distance_m,raw_tags)
                        VALUES (?,?,?,?,?,?,?,?,?)""",
                        (site_id, cat, ptype, str(pid), pname, plat, plon, d, ptags))
                    n_pois += 1
    conn.commit()
    print(f"\nStored {n_pois} POI-site pairs (within 2 km)")
    print("Per-category:")
    for cat, n in conn.execute("SELECT category,count(*) FROM pois GROUP BY 1 ORDER BY 2 DESC").fetchall():
        print(f"  {cat:<14} {n}")
    conn.close()

if __name__ == "__main__":
    main()
