"""Reproducible SPACE analysis. Dollars are billions of FY2025 dollars unless labeled.
Requires Python 3 and Matplotlib (python -m pip install matplotlib).
No revenue elasticities, official score, or probabilistic forecast is assumed.
"""
from pathlib import Path
import csv, json, math, shutil
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

ROOT=Path(__file__).resolve().parent
OUT=ROOT

def calculate():
    nasa, darpa=24.838,4.120
    core=3*(nasa+darpa)
    supplement=68.0
    annual=core+supplement
    reserve=2.5*core
    rows=[]
    for year in range(2027,2057):
        multiple={2027:1.75,2028:2.5}.get(year,3)
        share={2027:.5,2028:.75}.get(year,1)
        total=(nasa+darpa)*multiple+supplement*share
        rows.append({'fiscal_year':year,'agency_multiple':multiple,'nasa':nasa*multiple,'darpa_planning':darpa*multiple,
                     'other_accounts_assumed':supplement*share,'total_planning_authority':total,
                     'increase_over_flat_nasa_darpa_only':total-(nasa+darpa),
                     'nominal_at_2_percent_inflation':total*1.02**(year-2025),
                     'nominal_at_3_percent_inflation':total*1.03**(year-2025),
                     'nominal_at_4_percent_inflation':total*1.04**(year-2025)})
    contributions=[]
    for c in [25,50,100]:
        for r in [0,.02,.04]:
            target=annual*50
            years=math.ceil(target/c) if r==0 else math.ceil(math.log(1+target*r/c)/math.log(1+r))
            at50=c*50 if r==0 else c*((1+r)**50-1)/r
            contributions.append({'annual_contribution':c,'net_real_return':r,'years_to_target_without_payout':years,'principal_year_50':at50})
    sensitivity=[]
    for base in [100,200,300,400,500]:
        for rate in [.01,.04,.07,.10]:
            revenue=base*1000*rate/100
            sensitivity.append({'effective_taxable_base_trillions':base,'rate_percent':rate,'other_receipts':0,
                                'gross_cash_receipts':revenue,'operating_balance':revenue-annual,'coverage_ratio':revenue/annual,
                                'gap_to_105_percent':max(0,annual*1.05-revenue)})
    return {'version':1,'date':'2026-09-27','units':'Billions of constant FY2025 dollars except fields explicitly labeled',
      'assumptions':[
        'Source NASA baseline 24.838 and uncertified DARPA planning baseline 4.120.',
        'Source agency ramp 1.75x in FY2027, 2.50x in FY2028, then 3x.',
        'Analyst assumption: other 68B envelope phases 50%, 75%, then 100%; source does not specify a complete ramp.',
        'Authority is not obligations or outlays. Tables exclude reserve/endowment accumulation and credit subsidies.',
        'The incremental comparator is flat FY2025 NASA and DARPA only, not an official current-law baseline.',
        'Nominal examples assume constant inflation since FY2025; no actual GDP price-index series is represented.',
        'Revenue uses a hypothetical effective taxable base after avoidance and trading response. No empirical base or elasticity is estimated.',
        'Revenue excludes indirect income/payroll offsets, administration and timing effects; gross cash coverage is not federal deficit neutrality.',
        'Endowment scenarios begin after the reserve is funded, at zero principal, with end-year contributions and no payouts during accumulation.',
        'Net real returns are deterministic assumptions after expenses, not forecasts or guarantees; no likelihood is assigned.'
      ],
      'annual':annual,'protected_core':core,'other_envelope':supplement,'reserve':reserve,
      'reserve_full_envelope_months':reserve/annual*12,'endowment':annual*50,
      'endowment_payout_entry_principal':annual*25,'entry_payout_ceiling':annual*25*.02,
      'coverage_105_percent':annual*1.05,'effective_base_needed_at_004_trillions':annual*1.05/.0004/1000,
      'reserve_build_10_years_no_return':reserve/10,
      'darpa_spend_plan_sensitivity':{'baseline':4.408991,'floor':3*4.408991,'annual':74.514+3*4.408991+68,
        'annual_difference':3*(4.408991-darpa),'reserve':2.5*(74.514+3*4.408991), 'label':'Spend-plan sensitivity only; not certified enacted baseline'},
      'constant_envelope_arithmetic':{str(n):annual*n for n in [1,5,10,30,500]},
      'phased_totals':{str(n):sum(x['total_planning_authority'] for x in rows[:n]) for n in [5,10,30]},
      'full_other_accounts_from_first_year_totals':{str(n):(n*3-1.75)*(nasa+darpa)+n*supplement for n in [5,10,30]},
      'annual_rows':rows,'endowment_scenarios':contributions,'cash_sensitivities':sensitivity,
      'allocation':[['NASA',74.514],['DARPA planning floor',12.360],['Frontier Science Network',25],['Infrastructure',15],['Workforce and education',10],['Grand Challenges',10],['International projects',5],['Safety, oversight and data',3]]}

def figures(m):
    plt.rcParams.update({'font.family':'DejaVu Sans','font.size':11,'svg.fonttype':'none','svg.hashsalt':'space-act-2026','axes.spines.top':False,'axes.spines.right':False})
    fig,ax=plt.subplots(figsize=(10,5.6),layout='constrained')
    labels=[x[0] for x in m['allocation']][::-1]; values=[x[1] for x in m['allocation']][::-1]
    ax.barh(labels,values,color=['#738389']*6+['#25434c','#ad382f'])
    ax.set_xlim(0,87);ax.set_xlabel('Billions of FY2025 dollars per year')
    for i,v in enumerate(values):ax.text(v+.8,i,f'{v:,.3f}',va='center')
    ax.set_title('SPACE Act annual planning envelope',loc='left',pad=18)
    fig.text(.99,.01,'Source: SPACE Act of 2026. Illustrative authority, not an official score.',ha='right',fontsize=9)
    fig.savefig(OUT/'space-act-2026-funding.svg',metadata={'Date':None});plt.close(fig)
    fig,ax=plt.subplots(figsize=(10,5.6),layout='constrained')
    years=list(range(101))
    for r,color in [(0,'#738389'),(.02,'#25434c'),(.04,'#ad382f')]:
        ys=[50*y/1000 if not r else 50*((1+r)**y-1)/r/1000 for y in years]
        ax.plot(years,ys,label=f'{r:.0%} net real return',color=color,lw=2)
    ax.axhline(m['endowment']/1000,ls='--',color='#323232',label='$7.7437T target')
    ax.set_ylim(bottom=0);ax.set_xlabel('Years after reserve is funded');ax.set_ylabel('Trillions of FY2025 dollars')
    ax.set_title('$50B annual capitalization from zero principal',loc='left',pad=18);ax.legend(frameon=False)
    fig.text(.99,.01,'Illustrative constant returns; end-year contributions; no withdrawals; not a forecast.',ha='right',fontsize=9)
    fig.savefig(OUT/'space-act-2026-endowment.svg',metadata={'Date':None});plt.close(fig)
    for name in ['funding','endowment']:
        path=OUT/f'space-act-2026-{name}.svg'
        path.write_text('\n'.join(line.rstrip() for line in path.read_text().splitlines())+'\n')

if __name__=='__main__':
    model=calculate();OUT.mkdir(parents=True,exist_ok=True)
    (OUT/'space-act-2026-model.json').write_text(json.dumps(model,indent=2)+'\n')
    with (OUT/'space-act-2026-annual-model.csv').open('w') as f:
        w=csv.DictWriter(f,fieldnames=model['annual_rows'][0]);w.writeheader();w.writerows(model['annual_rows'])
    figures(model)
    # The downloadable script runs independently and emits the same outputs in its directory.
    source=Path(__file__).read_text().replace("ROOT=Path(__file__).resolve().parents[1]\nOUT=ROOT/'legislation/files'", "ROOT=Path(__file__).resolve().parent\nOUT=ROOT")
    (OUT/'space-act-2026-model.py').write_text(source)
    print(json.dumps({k:model[k] for k in ['annual','reserve','endowment','coverage_105_percent','phased_totals','darpa_spend_plan_sensitivity']},indent=2))
