r"""
Generate 3 staggered synthetic 2x2 flights (same course, distinct teams), each
scored, plus a manifest — input for the broadcast director/overlap engine.

Guns are 120 s apart so the races overlap in time, exercising the director's
fast-replay catch-up. Reuses synth_race's boat motion and score_race's engine.

  ..\.venv-demo\Scripts\python.exe export\gen_races.py
"""
import json
import math
import sys
from pathlib import Path

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))          # for synth_race (sibling)
sys.path.insert(0, str(HERE.parents[2] / "scoring"))             # the shared engine
import synth_race as S  # noqa: E402
from score_race import enrich  # noqa: E402

T0 = 1_780_000_000_000            # absolute gun for flight 1 (fixed, deterministic)
PRE, POST = 195, 360             # window: 195 s pre-start, 360 s after the gun
WIND = 350


def _ll(xy):
    la, lo = S.xy_to_latlon(*xy)
    return {"lat": round(la, 7), "lon": round(lo, 7)}


def _course():
    def wp(name, xy, rounding):
        la, lo = S.xy_to_latlon(*xy)
        return {"name": name, "type": "rounding", "rounding": rounding,
                "lat": round(la, 7), "lon": round(lo, 7)}
    return {
        "name": "Stand-in W/L",
        "center": {"lat": S.REF_LAT, "lon": S.REF_LON},
        "startLine": {"port": _ll(S.LINE_PORT), "starboard": _ll(S.LINE_STBD)},
        "finishLine": {"port": _ll(S.LINE_PORT), "starboard": _ll(S.LINE_STBD)},
        "waypoints": [wp("WM", S.WM, "port"), wp("LM", S.LM, "starboard")],
    }


def build_race(gun_ms, title, teams_cfg):
    track_start = gun_ms - PRE * 1000
    track_end = gun_ms + POST * 1000
    flat = []        # (global_idx, boat_cfg)
    for t in teams_cfg:
        for b in t["boats"]:
            flat.append((len(flat), b))

    frames = {}
    for sec in range(0, PRE + POST + 1):
        tg = sec - PRE
        fr = {}
        for bi, b in flat:
            if tg < 0:
                x, y, h = S.prestart_pos(bi, tg)
                spd = 1.2
            else:
                d = S.boat_distance(b["delay"], b["finish"], tg)
                x, y, h = S.pos_along(S.ROUTE, d)
                lane = (bi - 1.5) * 6.0
                x += math.cos(math.radians(h)) * lane
                y += -math.sin(math.radians(h)) * lane
                spd = max(0.0, d - S.boat_distance(b["delay"], b["finish"], tg - 1))
            la, lo = S.xy_to_latlon(x, y)
            fr[b["dev"]] = {"lat": round(la, 7), "lon": round(lo, 7),
                            "speed": round(spd, 2), "course": round(h, 1)}
        frames[str(sec)] = fr

    teams = [{
        "teamId": t["teamId"], "name": t["name"],
        "boats": [{"deviceId": b["dev"], "sailId": b["sail"], "visualId": f'{t["name"]} {b["sail"]}',
                   "boatId": None, "color": t["color"], "sternM": 1.5} for b in t["boats"]],
    } for t in teams_cfg]

    feed = {
        "schema": "vr-broadcast-demo/1", "source": "synthetic",
        "meta": {"title": title, "user": "GSYS", "instanceId": None, "groupId": None,
                 "openEnded": False, "raceType": "team_race_2",
                 "trackStartUtcMs": track_start, "gunUtcMs": gun_ms, "trackEndUtcMs": track_end,
                 "frameStepMs": 1000, "windFromDeg": WIND},
        "course": _course(), "teams": teams, "frames": frames, "video": [],
    }
    return enrich(feed)


# (gun offset, title, teams). Each team's trailing boat (higher finish_s) decides.
RACES = [
    (0, "Flight 1 — Blue v Yellow", [
        {"teamId": "blue", "name": "Team Blue", "color": "#1565C0",
         "boats": [{"dev": "r1-b1", "sail": "11", "delay": 0, "finish": 188},
                   {"dev": "r1-b2", "sail": "12", "delay": 3, "finish": 205}]},
        {"teamId": "yellow", "name": "Team Yellow", "color": "#F9A825",
         "boats": [{"dev": "r1-y1", "sail": "21", "delay": 1, "finish": 192},
                   {"dev": "r1-y2", "sail": "22", "delay": 1, "finish": 230}]},
    ]),
    (120000, "Flight 2 — Orange v Purple", [
        {"teamId": "orange", "name": "Team Orange", "color": "#FB8C00",
         "boats": [{"dev": "r2-o1", "sail": "31", "delay": 0, "finish": 190},
                   {"dev": "r2-o2", "sail": "32", "delay": 2, "finish": 232}]},
        {"teamId": "purple", "name": "Team Purple", "color": "#8E24AA",
         "boats": [{"dev": "r2-p1", "sail": "41", "delay": 1, "finish": 188},
                   {"dev": "r2-p2", "sail": "42", "delay": 1, "finish": 210}]},
    ]),
    (240000, "Flight 3 — Teal v Pink", [
        {"teamId": "teal", "name": "Team Teal", "color": "#00897B",
         "boats": [{"dev": "r3-t1", "sail": "51", "delay": 0, "finish": 188},
                   {"dev": "r3-t2", "sail": "52", "delay": 3, "finish": 206}]},
        {"teamId": "pink", "name": "Team Pink", "color": "#D81B60",
         "boats": [{"dev": "r3-k1", "sail": "61", "delay": 1, "finish": 192},
                   {"dev": "r3-k2", "sail": "62", "delay": 1, "finish": 228}]},
    ]),
]


def main():
    out_dir = HERE.parent / "data" / "races"
    out_dir.mkdir(parents=True, exist_ok=True)
    manifest = []
    for i, (off, title, teams) in enumerate(RACES, 1):
        feed = build_race(T0 + off, title, teams)
        with open(out_dir / f"race{i}.json", "w", encoding="utf-8") as f:
            json.dump(feed, f, ensure_ascii=False, separators=(",", ":"))
        m, res = feed["meta"], feed.get("result")
        manifest.append({
            "id": f"race{i}", "title": title, "feed": f"race{i}.json",  # relative to this manifest
            "trackStartUtcMs": m["trackStartUtcMs"], "gunUtcMs": m["gunUtcMs"],
            "trackEndUtcMs": m["trackEndUtcMs"],
            "winnerSec": res["winnerSec"] if res else None,
            "winnerName": res["winnerName"] if res else None,
        })
        print(f"race{i}: {title}  events={len(feed['events'])}  "
              f"winner={res['winnerName'] if res else None} @ {res['winnerSec'] if res else '-'}s")
    with open(out_dir / "manifest.json", "w", encoding="utf-8") as f:
        json.dump({"races": manifest, "params": {"winnerGraceS": 15, "preStartS": 30, "fastReplayX": 5}},
                  f, ensure_ascii=False, indent=1)
    print(f"wrote manifest with {len(manifest)} races")


if __name__ == "__main__":
    main()
