#!/usr/bin/env python3
"""Q5c score (DC A1): Engine paths + A1 growth reads, weighted to the true 5x / non-5x mix per half. V1 = Engine v1 trail."""
import csv, random, statistics, sys, collections, json
G = {r["coin"]: r for r in csv.DictReader(open(sys.argv[1]))}
NOPART = len(sys.argv) > 3 and sys.argv[3] == "nopartial"
P = {r["coin"].lower(): r for r in csv.DictReader(open("q5c_paths.csv")) if r["status"] == "ok" and not (NOPART and r.get("partial") in ("1.0", "1"))}
U = {r["token"].lower(): r for r in csv.DictReader(open("univ.csv"))}
EDGE = 528; random.seed(11)
f = lambda x: float(x) if x not in ("", None) else 0.0
true = collections.Counter((P[c]["half"], U[c]["hit5x"]) for c in P)
scored = [c for c in P if c in G and G[c]["src"] != ""]
have = collections.Counter((P[c]["half"], U[c]["hit5x"]) for c in scored)
W = {k: true[k] / have[k] for k in have}
rows = []
for c in scored:
    p, g = P[c], G[c]; w = W[(p["half"], U[c]["hit5x"])]
    o15, o60 = f(p["v1_15_open"]) > 0, f(p["v1_60_open"]) > 0
    fire = None
    if o15 and g["g15"] != "" and float(g["g15"]) >= EDGE: fire = "15"
    elif o60 and g["g60"] != "" and float(g["g60"]) >= EDGE: fire = "60"
    rows.append(dict(c=c, half=p["half"], x5=U[c]["hit5x"], w=w, o15=o15, o60=o60, fire=fire,
                     a15=f(p["v1_15_add_500"]), a60=f(p["v1_60_add_500"]), base=f(p["base_500"]), venue=p["venue"], bexit=p["base_exit"],
                     pulled15=(p["v1_15_exit"] == "pull"), pulled60=(p["v1_60_exit"] == "pull")))
out = {"weights": {"%s_%s" % k: round(v, 3) for k, v in W.items()}, "true": {"%s_%s" % k: v for k, v in true.items()}, "scored": {"%s_%s" % k: v for k, v in have.items()}}
for h in ("A", "B"):
    R = [r for r in rows if r["half"] == h]; F = [r for r in R if r["fire"]]
    add = [(r["a15"] if r["fire"] == "15" else r["a60"], r["w"]) for r in F]
    wsum = sum(w for _, w in add); tot = sum(a * w for a, w in add); mean = tot / wsum if wsum else None
    pool15 = [(r["a15"], r["w"]) for r in R if r["o15"]]; pool60 = [(r["a60"], r["w"]) for r in R if r["o60"]]
    beat = None
    if F:
        n15 = sum(1 for r in F if r["fire"] == "15"); n60 = len(F) - n15; win = 0
        for _ in range(10000):
            d = random.choices(pool15, weights=[w for _, w in pool15], k=n15) + (random.choices(pool60, weights=[w for _, w in pool60], k=n60) if n60 else [])
            win += mean > statistics.mean(a for a, _ in d)
        beat = round(win / 10000, 4)
    out["V1_" + h] = dict(coins=len(R), open15=len(pool15), fired=len(F), fired_x5=sum(1 for r in F if r["x5"] == "1"),
                          fired_weighted=round(wsum, 1), usd_added_weighted=round(tot), mean_added=round(mean, 1) if mean is not None else None,
                          trail_on_all_open15_mean=round(sum(a * w for a, w in pool15) / sum(w for _, w in pool15), 1) if pool15 else None, beats_random=beat)
for h in ("A", "B"):
    for ven in ("v4", "v3", "pons_grad"):
        R = [r for r in rows if r["half"] == h and r["venue"] == ven]; F = [r for r in R if r["fire"]]
        add = [(r["a15"] if r["fire"] == "15" else r["a60"], r["w"]) for r in F]; ws = sum(w for _, w in add)
        out["V1_%s_%s" % (h, ven)] = dict(coins=len(R), fired=len(F), usd_added_weighted=round(sum(a * w for a, w in add)),
            mean_added=round(sum(a * w for a, w in add) / ws, 1) if ws else None,
            fired_base_pulled=sum(1 for r in F if r["bexit"] == "pull"), fired_trail_exit_pull=sum(1 for r in F if (r["pulled15"] if r["fire"] == "15" else r["pulled60"])))
json.dump(out, open(sys.argv[2], "w"), indent=1); print(json.dumps(out, indent=1))
