#!/usr/bin/env python3
"""
Erweitert lg-roadnet.json um innsbruck und graz als Knoten. Neue Kanten:
  - muenchen-innsbruck   (A8/A93, ~170 km)
  - innsbruck-salzburg   (A12/A10 ueber Loferer Hochtal, ~190 km)
  - innsbruck-mailand    (A13+A22 Brenner, ~390 km)
  - wien-graz            (A2 Sued, ~200 km)
  - salzburg-graz        (A10+A9 via Tauerntunnel+Liezen, ~280 km)

Polylines per OSRM holen + Douglas-Peucker mit ~110 m Toleranz.
"""
import json
import math
import ssl
import time
import urllib.request
from pathlib import Path

ROADNET = Path(__file__).resolve().parents[3] / "assets" / "data" / "lg-roadnet.json"
LOCATIONS = Path(__file__).resolve().parents[3] / "assets" / "data" / "lg-locations.json"
TOLERANCE_DEG = 0.001

SSL_CTX = ssl.create_default_context()
SSL_CTX.check_hostname = False
SSL_CTX.verify_mode = ssl.CERT_NONE
OSRM = "https://router.project-osrm.org/route/v1/driving/{coords}?overview=full&geometries=geojson"


def perp_dist(pt, a, b):
    dx, dy = b[0] - a[0], b[1] - a[1]
    if dx == 0 and dy == 0:
        return math.hypot(pt[0] - a[0], pt[1] - a[1])
    t = max(0.0, min(1.0, ((pt[0] - a[0]) * dx + (pt[1] - a[1]) * dy) / (dx*dx + dy*dy)))
    return math.hypot(pt[0] - (a[0] + t*dx), pt[1] - (a[1] + t*dy))


def rdp(points, eps):
    if len(points) < 3:
        return list(points)
    max_d, idx = 0.0, 0
    for i in range(1, len(points) - 1):
        d = perp_dist(points[i], points[0], points[-1])
        if d > max_d:
            max_d, idx = d, i
    if max_d <= eps:
        return [points[0], points[-1]]
    return rdp(points[:idx+1], eps)[:-1] + rdp(points[idx:], eps)


def fetch(waypoints):
    coords = ";".join(f"{w[1]},{w[0]}" for w in waypoints)
    with urllib.request.urlopen(OSRM.format(coords=coords), timeout=30, context=SSL_CTX) as r:
        data = json.load(r)
    route = data["routes"][0]
    poly = [[round(c[1], 5), round(c[0], 5)] for c in route["geometry"]["coordinates"]]
    return poly, route["distance"] / 1000.0


def main():
    net = json.loads(ROADNET.read_text(encoding="utf-8"))
    locs = {l["id"]: l for l in json.loads(LOCATIONS.read_text(encoding="utf-8"))}

    # Neue Knoten
    existing_ids = {n["id"] for n in net["nodes"]}
    for nid in ("innsbruck", "graz"):
        if nid in existing_ids:
            continue
        loc = locs[nid]
        net["nodes"].append({"id": nid, "locationId": nid, "name": loc["name"]})

    # Neue Kanten
    NEW_EDGES = [
        ("muenchen-innsbruck",   "muenchen",   "innsbruck", 170, "A8/A93"),
        ("innsbruck-salzburg",   "innsbruck",  "salzburg",  190, "A12/A93/A10"),
        ("innsbruck-mailand",    "innsbruck",  "mailand",   390, "A13/A22 Brenner"),
        ("wien-graz",            "wien",       "graz",      200, "A2 Sued"),
        ("salzburg-graz",        "salzburg",   "graz",      280, "A10/A9 Tauern+Liezen"),
    ]
    existing_edge_ids = {e["id"] for e in net["edges"]}

    for eid, fnode, tnode, dist, code in NEW_EDGES:
        if eid in existing_edge_ids:
            print(f"skip {eid} (schon da)")
            continue
        fl = locs[net["nodes"][[n["id"] for n in net["nodes"]].index(fnode)]["locationId"]]
        tl = locs[net["nodes"][[n["id"] for n in net["nodes"]].index(tnode)]["locationId"]]
        start = [fl["lat"], fl["lon"]]
        end   = [tl["lat"], tl["lon"]]
        print(f"-> {eid}: OSRM [{start}] -> [{end}] ...", flush=True)
        try:
            poly, osrm_km = fetch([start, end])
            poly = rdp(poly, TOLERANCE_DEG)
            net["edges"].append({
                "id": eid, "from": fnode, "to": tnode,
                "distanceKm": dist, "routeCode": code,
                "polyline": poly,
                "distanceKmOsrm": round(osrm_km, 1),
            })
            print(f"   {osrm_km:.0f} km real, {len(poly)} Punkte")
        except Exception as e:
            print(f"   FEHLER: {e}")
        time.sleep(1.1)

    ROADNET.write_text(
        json.dumps(net, ensure_ascii=False, separators=(",", ":")),
        encoding="utf-8",
    )
    sz = ROADNET.stat().st_size / 1024
    print(f"\nFertig: {len(net['edges'])} Kanten, {sz:.1f} KB")


if __name__ == "__main__":
    main()
