# -*- coding: utf-8 -*-
"""Digitalizacija: rute.json (waypointi) + places.json (koordinate) -> BRouter ->
geojson/rN.geojson + gpx/rN.gpx + stats.json.

Waypoint u rute.json smije biti ključ mjesta ("gola") ILI inline via-točka [lon, lat]
za fino usmjeravanje na točno određenu cestu. Ponovno pokretanje regenerira sve.
"""
import json, os, time, urllib.request, urllib.parse

BASE = os.path.dirname(os.path.abspath(__file__))
UA = {"User-Agent": "BikeCross-digitizer/1.0 (info@weblink.hr)"}
BROUTER = "https://brouter.de/brouter"

places = json.load(open(os.path.join(BASE, "places.json"), encoding="utf-8"))
cfg = json.load(open(os.path.join(BASE, "rute.json"), encoding="utf-8"))
os.makedirs(os.path.join(BASE, "geojson"), exist_ok=True)
os.makedirs(os.path.join(BASE, "gpx"), exist_ok=True)

def coord(wp):
    if isinstance(wp, list):          # inline [lon, lat]
        return wp[0], wp[1], "via"
    p = places[wp]
    if p["lat"] is None:
        raise ValueError(f"mjesto '{wp}' nema koordinate u places.json")
    return p["lon"], p["lat"], wp

def haversine_m(a, b):
    import math
    la1, la2 = math.radians(a[1]), math.radians(b[1])
    dla, dlo = la2 - la1, math.radians(b[0] - a[0])
    h = math.sin(dla/2)**2 + math.cos(la1)*math.cos(la2)*math.sin(dlo/2)**2
    return 12742000 * math.asin(math.sqrt(h))

def split_segments(waypoints):
    """Waypoint smije biti i {"rucno": [[lon,lat],...]} — ručno iscrtan segment
    (npr. put koji ne postoji u OSM-u). Vraća [("route", wps), ("manual", coords), ...]"""
    segs, cur = [], []
    for wp in waypoints:
        if isinstance(wp, dict) and "rucno" in wp:
            man = wp["rucno"]
            cur.append(man[0])
            if len(cur) >= 2:
                segs.append(("route", cur))
            segs.append(("manual", man))
            cur = [man[-1]]
        else:
            cur.append(wp)
    if len(cur) >= 2:
        segs.append(("route", cur))
    return segs

def brouter(lonlats, profile, nogos=None):
    params = {
        "lonlats": "|".join(f"{lon:.6f},{lat:.6f}" for lon, lat in lonlats),
        "profile": profile, "alternativeidx": 0, "format": "geojson"}
    if nogos:
        # nogo zone: krug (lon, lat, radijus u m) koji ruta MORA zaobići
        params["nogos"] = "|".join(f"{n[0]:.6f},{n[1]:.6f},{int(n[2])}" for n in nogos)
    url = BROUTER + "?" + urllib.parse.urlencode(params)
    last = None
    for attempt in range(3):
        try:
            req = urllib.request.Request(url, headers=UA)
            with urllib.request.urlopen(req, timeout=120) as r:
                return json.loads(r.read().decode())
        except Exception as e:
            last = e
            time.sleep(3 * (attempt + 1))
    raise last

def to_gpx(name, coords):
    pts = "\n".join(
        f'      <trkpt lat="{c[1]:.6f}" lon="{c[0]:.6f}">' +
        (f"<ele>{c[2]:.1f}</ele>" if len(c) > 2 else "") + "</trkpt>"
        for c in coords)
    return f'''<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="WebLink BikeCross digitizer" xmlns="http://www.topografix.com/GPX/1/1">
  <trk><name>{name}</name><trkseg>
{pts}
  </trkseg></trk>
</gpx>
'''

stats = []
for r in cfg["rute"]:
    labels = []
    for wp in r["waypoints"]:
        if isinstance(wp, dict) and "rucno" in wp:
            labels.append("rucno")
        else:
            lon, lat, lab = coord(wp)
            labels.append(lab)
    try:
        coords_all, len_m, asc_total, t_total = [], 0, 0, 0
        for kind, seg in split_segments(r["waypoints"]):
            if kind == "manual":
                pts = [list(c) for c in seg]
                len_man = sum(haversine_m(seg[i], seg[i+1]) for i in range(len(seg)-1))
                len_m += len_man
                t_total += len_man / 1000 / 12 * 3600  # 12 km/h
            else:
                lonlats = [(c[0], c[1]) if isinstance(c, list) else coord(c)[:2] for c in seg]
                sgj = brouter(lonlats, cfg.get("profil", "trekking"), r.get("nogos"))
                sp = sgj["features"][0]["properties"]
                pts = sgj["features"][0]["geometry"]["coordinates"]
                len_m += int(sp.get("track-length", 0))
                asc_total += int(sp.get("filtered ascend", 0))
                t_total += float(sp.get("total-time", 0))
            if coords_all and pts and coords_all[-1][:2] == pts[0][:2]:
                pts = pts[1:]
            coords_all.extend(pts)
        gj = {"type": "FeatureCollection", "features": [{"type": "Feature",
              "geometry": {"type": "LineString", "coordinates": coords_all}, "properties": {}}]}
        feat = gj["features"][0]
        length_km = round(len_m / 1000, 1)
        ascend = asc_total
        t_min = round(t_total / 60)
        feat["properties"] = {
            "id": r["id"], "naziv": r["naziv"], "tip": r["tip"],
            "prekogranicna": r["prekogranicna"], "duljina_km": length_km,
            "uspon_m": ascend, "trajanje_min_brouter": t_min,
            "waypoints": labels, "profil": cfg.get("profil", "trekking"),
            "izvor": "BRouter/OSM draft — čeka pregled",
        }
        with open(os.path.join(BASE, "geojson", f"{r['id'].lower()}.geojson"), "w", encoding="utf-8") as f:
            json.dump(gj, f, ensure_ascii=False)
        with open(os.path.join(BASE, "gpx", f"{r['id'].lower()}.gpx"), "w", encoding="utf-8") as f:
            f.write(to_gpx(f"{r['id']} {r['naziv']}", feat["geometry"]["coordinates"]))
        stats.append({"id": r["id"], "naziv": r["naziv"], "tip": r["tip"],
                      "duljina_km": length_km, "uspon_m": ascend})
        print(f"{r['id']}: {length_km:6.1f} km  uspon {ascend:3d} m   {r['naziv']}")
    except Exception as e:
        stats.append({"id": r["id"], "naziv": r["naziv"], "greska": str(e)})
        print(f"{r['id']}: GREŠKA — {e}")
    time.sleep(1.5)

with open(os.path.join(BASE, "stats.json"), "w", encoding="utf-8") as f:
    json.dump(stats, f, ensure_ascii=False, indent=2)
print("\nOK -> geojson/, gpx/, stats.json")
