"""Lever-table deltas from the CURRENT balanced base (how-we-modeled-risk §08 / model-docs §2.5).
Runs cost_recovery_mc on the balanced config with one lever perturbed at a time.
Reproducible (same SEED as the model).

v2.2 (audit): TWO corrections. (1) This script previously imported the SUPERSEDED
montecarlo_robust -- so the published lever tables were generated by the retired pre-v2
model and drifted from the promoted one (strict-cliff 71->67, all-three-fears 66->64,
etc., every drift in the favorable direction). It now imports the live model. (2) It now
WRITES sensitivity_levers_output.json so the site tables can render from data instead of
hand-carried numbers that can go stale again.
Run:  python sensitivity_levers.py
"""
import json
from montecarlo_v2 import cost_recovery_mc, county_value_mc, SCENARIOS, MODEL_VERSION, FIXED_SHARE_BRACKET

BAL = dict(SCENARIOS['balanced'])   # headline base = always-on conservative bandwidth (never pinned)

def run(key, label, **over):
    scn = dict(BAL); scn.update(over)
    p = cost_recovery_mc(scn=scn, verbose=False)['p_payback']
    return {"key": key, "label": label, "p": p}

base = cost_recovery_mc(scn=dict(BAL), verbose=False)['p_payback']
rows = [
    run('starlink_surge',  'FEAR  Starlink surge (+2%/yr churn)',      starlink=0.02),
    run('shock',           'FEAR  Reseller/market shock (~20%)',       shock=0.20),
    run('pricewar',        'FEAR  NCI price war (-2 pts, 3yr)',        pricewar=0.02),
    run('rt0',             'CHOICE Rate lags inflation fully (RT0)',   rate_track=0.0),
    run('true_freeze',     'CHOICE Rate LITERALLY frozen (2009 record)', rate_track=0.0, freeze_rate=1),
    run('cliff',           'CHOICE Strictest wear-out accounting',     cliff=True),
    run('strip',           'SKEPTIC Strip retention+funded-growth',    sticky=0.0, community=0.0, coverage=0.0),
    run('bw_zero',         'STRESS bandwidth hypothetically zero',     bw_mbps=0.0),
    run('bw_full',         'UPSIDE bandwidth at documented 2.8 Mbps',  bw_mbps=2.8),
    run('bw_price',        'WHATIF price drops $1.50->$1.00',          bw_price=1.00),
    run('fixed30',         'STRUCTURE 30% of opex fixed (v2.2 bracket)', fixed_share=FIXED_SHARE_BRACKET[0]),
    run('fixed50',         'STRUCTURE 50% of opex fixed (v2.2 bracket)', fixed_share=FIXED_SHARE_BRACKET[1]),
    run('all_fears',       'ALL THREE FEARS together',                 starlink=0.02, shock=0.20, pricewar=0.02),
    run('delay1',          'DELAY  build delayed 1 year',              delay=1.0),
    run('delay2',          'DELAY  build delayed 2 years',             delay=2.0),
    run('delay3',          'DELAY  build delayed 3 years',             delay=3.0),
    # --- card-specific settings (fear/upside rebuttal cards on the page) ---
    run('card_starlink3',  'CARD  Starlink surge +3%/yr',              starlink=0.03),
    run('card_shock25',    'CARD  market shock 25% one-time',          shock=0.25),
    run('card_no_sticky',  'CARD  remove stickiness only',             sticky=0.0),
    run('card_no_community','CARD  remove community only',             community=0.0),
]

print(f"\nBALANCED BASE : {base:.1f}%\n" + "-" * 60)
for r in rows:
    print(f"  {r['label']:46s} {r['p']:5.1f}%   ({r['p'] - base:+.1f})")

out = {"_model_version": MODEL_VERSION, "base": base,
       "basis": ("One lever perturbed at a time from the Balanced base, full 200,000-run model, "
                 "locked seed. p = P(discounted payback within the scenario's accounting deadline). "
                 "Generated by sensitivity_levers.py from montecarlo_v2 -- regenerate this file "
                 "whenever the model version changes."),
       "rows": {r['key']: {"label": r['label'], "p": r['p'], "delta": round(r['p'] - base, 1)} for r in rows}}
json.dump(out, open("sensitivity_levers_output.json", "w"), indent=1)
print("\n[wrote sensitivity_levers_output.json]")
