"""Illustrative annual fiscal accounting, not an estimated macroeconomic forecast.
Run: python3 model.py. Standard library only. No external/private inputs.
All monetary values are percentage points of baseline annual GDP (GDP=100).
"""
from dataclasses import dataclass, asdict, replace
from pathlib import Path
import csv, json, math, hashlib

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

@dataclass(frozen=True)
class Inputs:
    adoption: float
    productivity_uplift: float
    disruption_output_loss: float
    worker_share_new_value: float
    wage_to_profit_shift: float
    labor_tax_yield: float
    capital_tax_yield: float
    transition_spending: float
    admin_share: float = .05
    eligible_population_share: float = 1.0
    promised_transfer: float = 0.0

def calculate(p):
    for name in ('adoption','productivity_uplift','worker_share_new_value','labor_tax_yield','capital_tax_yield','admin_share'):
        assert 0 <= getattr(p,name) <= 1, name
    assert p.admin_share < 1 and 0 < p.eligible_population_share <= 1
    assert min(p.disruption_output_loss,p.wage_to_profit_shift,p.transition_spending,p.promised_transfer) >= 0
    gross = 100*p.adoption*p.productivity_uplift
    net = gross-p.disruption_output_loss
    wage = p.worker_share_new_value*net-p.wage_to_profit_shift
    capital = (1-p.worker_share_new_value)*net+p.wage_to_profit_shift
    wage_tax, capital_tax = wage*p.labor_tax_yield, capital*p.capital_tax_yield
    revenue = wage_tax+capital_tax
    budget = max(0,revenue-p.transition_spending)
    dividend, administration = budget*(1-p.admin_share), budget*p.admin_share
    existing_gap = max(0,p.transition_spending-revenue)
    promise_gross = p.promised_transfer/(1-p.admin_share)
    promise_gap = max(0,p.transition_spending+promise_gross-revenue) if p.promised_transfer else 0
    r = dict(gross_productivity_gain=gross,disruption_output_loss=p.disruption_output_loss,
       net_output_gain=net,wage_income_change=wage,capital_income_change=capital,
       labor_tax_change=wage_tax,capital_tax_change=capital_tax,incremental_tax_revenue=revenue,
       transition_spending=p.transition_spending,dividend_admin_cost=administration,
       funded_dividend=dividend,other_funding_needed=existing_gap,
       annual_per_person_pct_baseline_gdp_per_capita=dividend/p.eligible_population_share,
       promised_transfer=p.promised_transfer,promise_admin_cost=promise_gross-p.promised_transfer,
       promise_funding_gap=promise_gap)
    assert math.isclose(wage+capital,net,abs_tol=1e-10), 'Income/output identity'
    assert math.isclose(revenue+existing_gap,p.transition_spending+dividend+administration,abs_tol=1e-10), 'Budget identity'
    assert dividend >= 0 and administration >= 0
    return r

inclusive=Inputs(.60,.12,.50,.60,1.0,.20,.25,.40)
cases=[
 ('inclusive','Inclusive gains',inclusive),
 ('concentrated','Concentrated returns',Inputs(.60,.12,.50,.15,3.0,.20,.05,.60)),
 ('weak','Weak gains and disruption',Inputs(.25,.04,1.50,.40,2.0,.20,.15,.60)),
 ('unfunded','Promise before funding',replace(inclusive,promised_transfer=4.0)),
]

def tests():
    zero=Inputs(0,0,0,.5,0,.2,.2,0,0)
    assert all(v==0 for v in calculate(zero).values())
    assert calculate(replace(zero,adoption=1,productivity_uplift=.1))['net_output_gain']==10
    assert calculate(replace(inclusive,admin_share=0))['funded_dividend'] > calculate(inclusive)['funded_dividend']
    assert math.isclose(calculate(replace(inclusive,eligible_population_share=.5))['annual_per_person_pct_baseline_gdp_per_capita'],2*calculate(inclusive)['funded_dividend'])
    for invalid in [replace(zero,adoption=1.1),replace(zero,eligible_population_share=0),replace(zero,admin_share=1)]:
        try: calculate(invalid)
        except AssertionError: pass
        else: raise AssertionError('Invalid inputs accepted')
    for a in [0,.25,.5,1]:
        for t in [0,.05,.25,.5,1]: calculate(replace(inclusive,adoption=a,capital_tax_yield=t))
    # Wage-to-profit shifts never manufacture additional output.
    assert math.isclose(calculate(replace(inclusive,wage_to_profit_shift=5))['net_output_gain'],calculate(inclusive)['net_output_gain'])
    # Equal tax yields make the wage/capital split irrelevant to incremental revenue.
    x=replace(inclusive,labor_tax_yield=.2,capital_tax_yield=.2)
    assert math.isclose(calculate(x)['incremental_tax_revenue'],calculate(replace(x,wage_to_profit_shift=5,worker_share_new_value=.1))['incremental_tax_revenue'])
    return 'PASS: budget and income identities, zero and adoption endpoints, eligibility scaling, invalid inputs, administration, income reallocation, tax symmetry, sensitivity grid'

def main():
    metadata=dict(title='Can AI finance a universal dividend?',status='Executed illustrative deterministic scenarios',
      verified_date='2026-10-27',horizon='One annual accounting period after the assumed deployment; not a calendar-year forecast or cumulative total',
      units='Percentage points of baseline annual gross domestic product (GDP); baseline GDP=100',
      prices='Constant baseline purchasing-power units; no currency or exchange-rate forecast',
      population='All residents, including children, share the transfer equally. Population held fixed. No age or citizenship forecast.',
      parameter_status='All numeric model inputs are author-selected teaching assumptions, not empirical estimates or IMF forecasts.',
      model_scope='Partial fiscal and income accounting, not a general-equilibrium, employment, inflation, poverty or welfare model.',
      reproducibility='python3 model.py; Python standard library only; deterministic; no random seed needed')
    scenarios=[dict(id=i,title=t,inputs=asdict(p),results=calculate(p)) for i,t,p in cases]
    (ROOT/'scenarios.json').write_text(json.dumps(dict(metadata=metadata,scenarios=scenarios),indent=2)+'\n')
    rows=[dict(id=s['id'],title=s['title'],**s['results']) for s in scenarios]
    with (ROOT/'scenarios.csv').open('w',newline='') as f:
        w=csv.DictWriter(f,fieldnames=rows[0].keys());w.writeheader();w.writerows(rows)
    sens=[]
    for a in [0,.15,.30,.45,.60,.75,.90,1.0]:
      for t in [0,.05,.10,.15,.20,.25,.30,.35,.40]:
        r=calculate(replace(inclusive,adoption=a,capital_tax_yield=t))
        sens.append(dict(adoption=a,capital_tax_yield=t,funded_dividend=r['funded_dividend'],other_funding_needed=r['other_funding_needed']))
    (ROOT/'sensitivity.json').write_text(json.dumps(dict(note='One-factor/grid sensitivity around inclusive case; fixed disruption, wage shift and transition cost even at zero adoption represent a failed deployment. Not probability intervals.',rows=sens),indent=2)+'\n')
    report=tests()
    (ROOT/'test-results.txt').write_text(report+'\n')
    print(report)
    for s in scenarios: print(s['title'],json.dumps(s['results']))
    manifest={p.name:hashlib.sha256(p.read_bytes()).hexdigest() for p in ROOT.iterdir() if p.is_file() and p.name!='manifest.json'}
    (ROOT/'manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')

if __name__=='__main__': main()
