#!/usr/bin/env python3
"""Regenerate the synthetic demo cohort for Patient Recall Engine.

Writes app/data.js. Deterministic: same seed gives the same 260 patients.
This is SYNTHETIC data. It contains no PHI and is not derived from any real
patient record. It is shaped like a PMS export so the app exercises the same
code paths a real Dentrix/Open Dental extract would.

    python3 tools/generate_cohort.py [--n 260] [--seed 20260812]
"""
import argparse, datetime, json, math, random, pathlib

FIRST_M = "James Robert John Michael David William Richard Thomas Chris Daniel Matt Anthony Mark Steven Andrew Kevin Brian Jason Ryan Eric Jacob Nathan Gary Dennis Carlos Miguel Andre Trevor Wesley Omar".split()
FIRST_F = "Mary Patricia Jennifer Linda Elizabeth Barbara Susan Jessica Sarah Karen Nancy Lisa Betty Sandra Margaret Ashley Kimberly Emily Donna Michelle Carol Amanda Melissa Deborah Rachel Maria Sofia Priya Nicole Hannah Grace Tanya Yolanda".split()
LAST = """Anderson Baker Bennett Brooks Bryant Campbell Carter Chen Coleman Cooper Diaz Duncan Ellis Fisher Foster Garcia Gonzales Graham Grant Griffin Hayes Henderson Hoffman Hughes Jenkins Kaur Kim Lambert Lawson Lopez Marshall Mendoza Morrison Nguyen Okafor Olsen Ortiz Patel Pearson Perry Ramirez Reyes Rhodes Rivera Russo Sanders Schultz Sharma Simmons Sullivan Tran Vaughn Wallace Ward Weaver Webb Whitaker Wong Yates Zimmerman""".split()
PROCS = [("Prophy + exam",.42),("Perio maintenance",.14),("Composite filling",.15),("Crown seat",.09),
         ("Emergency exam / palliative",.08),("Root canal",.04),("Extraction",.04),("Whitening / cosmetic",.04)]
REASONS = [("Drifted / no reason on file",.44),("Insurance changed",.17),("Cost concern noted",.13),
           ("Moved out of area",.10),("Scheduling friction",.09),("Service complaint on file",.07)]

def wpick(rng, pairs):
    r, c = rng.random(), 0
    for v, w in pairs:
        c += w
        if r <= c: return v
    return pairs[-1][0]

def make(rng, i, today):
    male = rng.random() < .47
    name = f"{rng.choice(FIRST_M if male else FIRST_F)} {rng.choice(LAST)}"
    age = int(min(88, max(6, rng.gauss(44, 17))))
    months = rng.choices([13,14,15,16,18,20,22,24,27,30,34,38,44,52,60],
                         weights=[13,11,10,9,9,8,7,7,6,5,4,4,3,2,2])[0]
    prior = max(1, int(rng.gauss(7 if months < 26 else 4, 3.4)))
    insurance = rng.random() < .66
    reason = wpick(rng, REASONS)
    distance = round(rng.uniform(24,180),1) if reason == "Moved out of area" else round(abs(rng.gauss(6.5,6.2))+.4,1)
    return dict(
        id=f"P-{10000+i}", name=name, age=age, months=months,
        lastVisit=(today - datetime.timedelta(days=int(months*30.4))).isoformat(),
        priorVisits=prior, tenure=round(min(22, max(.5, prior*rng.uniform(.45,.95))),1),
        noShows=rng.choices([0,0,0,1,1,2,3],[40,18,12,14,8,5,3])[0],
        insurance=insurance,
        unusedBenefits=rng.choice([0,0,250,400,600,750,900,1100,1250,1500]) if insurance else 0,
        balance=rng.choices([0,0,0,45,120,240,410,680,940],[42,14,10,8,8,7,5,4,2])[0],
        lastProc=wpick(rng, PROCS), reason=reason,
        txPending=rng.choices([0,0,0,340,610,890,1450,2200,3400,5200],[30,12,10,10,10,8,8,6,4,2])[0],
        familyActive=rng.random() < .31, hasMobile=rng.random() < .88,
        emailOk=rng.random() < .79, priorReply=rng.random() < .34, distance=distance,
        provider=rng.choice(["Dr. Alvarez","Dr. Whitfield","Dr. Nnamdi"]),
        hygienist=rng.choice(["Kelsey","Dana","Marisol","Priya"]))

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--n", type=int, default=260)
    ap.add_argument("--seed", type=int, default=20260812)
    ap.add_argument("--out", default=str(pathlib.Path(__file__).parent.parent / "app" / "data.js"))
    a = ap.parse_args()
    rng = random.Random(a.seed)
    today = datetime.date(2026, 8, 12)
    pts = [make(rng, i, today) for i in range(1, a.n + 1)]
    hdr = (f"// Patient Recall Engine - synthetic demo cohort ({a.n} lapsed patients)\n"
           f"// Structurally modeled on a 3-op general practice PMS export.\n"
           f"// SYNTHETIC. No PHI. Regenerate: python3 tools/generate_cohort.py --seed {a.seed}\n")
    pathlib.Path(a.out).write_text(hdr + "const PATIENTS = " + json.dumps(pts, separators=(",", ":")) + ";\n")
    print(f"wrote {a.out}: {a.n} patients")

if __name__ == "__main__":
    main()
