"""Recompute selected historical Sentinel costs. No network or new source research.

From the downloadable files: python sentinel-analysis.py --data sentinel.json
--output figures --no-plots. Omit --no-plots with matplotlib==3.10.8 installed
to reproduce the chart. The input is manually transcribed, source-checked data;
this calculation does not independently verify source truth.
"""
from pathlib import Path
from decimal import Decimal
import argparse
import csv
import json

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--data', type=Path, default=Path(__file__).resolve().parents[1] / 'data/sentinel.json')
parser.add_argument('--output', type=Path, default=Path(__file__).resolve().parents[1] / 'publications')
parser.add_argument('--no-plots', action='store_true')
args = parser.parse_args()
data = json.loads(args.data.read_text())
args.output.mkdir(parents=True, exist_ok=True)
D = lambda x: Decimal(str(x))
rows = data['cost_comparisons']
baseline = sum(D(x['baseline']) for x in rows)
comparison = sum(D(x['pre_review']) for x in rows)
delta = comparison - baseline
milcon = next(x for x in rows if x['category'] == 'Military construction')
milcon_delta = D(milcon['pre_review']) - D(milcon['baseline'])
assert baseline == D('77740.7') and comparison == D('106426.9')
assert sum(D(x['then_year']) for x in rows) == D('152413.0')
result = {
    'edition': data['edition'], 'evidence_cutoff': data['evidence_cutoff'],
    'scope': '2020 baseline vs pre-July-2024-review PB2025 estimate; not a current 2026 estimate',
    'units': 'USD million', 'price_basis': 'constant FY2020 dollars',
    'baseline': str(baseline), 'pre_review_estimate': str(comparison),
    'increase': str(delta), 'increase_percent': str(delta / baseline * 100),
    'milcon_increase': str(milcon_delta),
    'milcon_share_of_increase_percent': str(milcon_delta / delta * 100),
    'baseline_quantity': 659, 'comparison_quantity': 659,
    'fy2026_emd_funding_components_million': ['2616.352', '2189.000'],
    'fy2026_emd_displayed_total_million': str(D('2616.352') + D('2189.000')),
    'fy2027_emd_request_million': '4521.370',
    'later_140_9bn_dollar_basis': None,
    'source_ids': ['n01', 'n06'],
}
(args.output / 'sentinel-calculations.json').write_text(json.dumps(result, indent=2) + '\n')
with (args.output / 'sentinel-costs.csv').open('w', newline='') as f:
    writer = csv.writer(f, lineterminator='\n')
    writer.writerow(['category', 'baseline_million', 'pre_review_million', 'increase_million', 'price_basis', 'source_id'])
    for row in rows:
        writer.writerow([row['category'], str(D(row['baseline'])), str(D(row['pre_review'])),
                         str(D(row['pre_review']) - D(row['baseline'])), 'constant FY2020 USD', 'n01'])
    writer.writerow(['TOTAL', str(baseline), str(comparison), str(delta), 'constant FY2020 USD', 'n01'])
if not args.no_plots:
    import matplotlib
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt
    plt.rcParams.update({'font.family': 'DejaVu Sans', 'font.size': 11, 'svg.fonttype': 'none',
                         'svg.hashsalt': 'sentinel-20260924', 'text.color': '#18313b',
                         'text.parse_math': False, 'axes.labelcolor': '#18313b', 'xtick.color': '#18313b', 'ytick.color': '#18313b'})
    fig, ax = plt.subplots(figsize=(9.2, 5.6), facecolor='#fffefa')
    fig.subplots_adjust(left=.23, right=.95, top=.69, bottom=.23)
    ax.set_facecolor('#fffefa')
    positions = list(range(len(rows)))
    ax.barh([y - .19 for y in positions], [x['baseline'] / 1000 for x in rows], height=.32, color='#146361', label='September 2020 baseline')
    ax.barh([y + .19 for y in positions], [x['pre_review'] / 1000 for x in rows], height=.32, color='#985018', label='Pre-review PB2025 estimate')
    for i, row in enumerate(rows):
        for key, offset in [('baseline', -.19), ('pre_review', .19)]:
            value = row[key] / 1000
            ax.text(value + .6, i + offset, f'{value:.2f}', va='center', fontsize=10)
    ax.set_yticks(positions, [x['category'] for x in rows])
    ax.invert_yaxis(); ax.set_xlim(0, 66)
    ax.set_xlabel('Acquisition estimate · USD billions · constant FY2020 dollars', labelpad=10)
    ax.xaxis.grid(True, color='#d6dcd7', linewidth=.6); ax.set_axisbelow(True)
    for spine in ax.spines.values(): spine.set_visible(False)
    ax.tick_params(axis='both', length=0)
    fig.text(.045, .94, 'Sentinel: the historical, same-dollar cost increase', fontsize=17, weight='bold')
    fig.text(.045, .89, '$77.74bn → $106.43bn  |  +36.90%  |  659 end items in both estimates', fontsize=12)
    handles, labels = ax.get_legend_handles_labels()
    fig.legend(handles, labels, loc='upper left', bbox_to_anchor=(.035, .845), ncol=2, frameon=False)
    fig.text(.045, .105, 'Source: Air Force December 2023-labeled MSAR, pp. 13, 16; PB2025 estimate before July 2024 review.', fontsize=9)
    fig.text(.045, .066, 'Not a 2026 baseline or cash spending. The later $140.9bn statement is not mixed into this series.', fontsize=9)
    for suffix in ('svg', 'png'):
        metadata = {'Date': None, 'Creator': 'Program Receipts'} if suffix == 'svg' else {'Software': 'Program Receipts'}
        fig.savefig(args.output / ('sentinel-historical-costs.' + suffix), dpi=180, metadata=metadata)
        if suffix == 'svg':
            svg = args.output / 'sentinel-historical-costs.svg'
            svg.write_text('\n'.join(line.rstrip() for line in svg.read_text().splitlines()) + '\n')
    plt.close(fig)
print(json.dumps(result, indent=2))
