"""Reproduce Morphed's September 22, 2026 pricing study.

Download packages.csv into this script's directory, then run:
  uv run --with matplotlib reproduce.py

This script analyzes the frozen observations; it does not fetch live prices.
"""
import csv
import json
from decimal import Decimal
from pathlib import Path
from statistics import median

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

ROOT = Path(__file__).resolve().parent
with (ROOT / 'packages.csv').open() as f:
    rows = list(csv.DictReader(f))
for row in rows:
    row['price'] = Decimal(row['price_usd'])
    row['outputs'] = int(row['included_outputs'])
    row['unit_price'] = row['price'] / row['outputs']

prices = [r['price'] for r in rows]
units = [r['unit_price'] for r in rows]
summary = {
    'observed_date': '2026-09-22',
    'providers': len({r['provider'] for r in rows}),
    'packages': len(rows),
    'median_package_usd': str(median(prices)),
    'min_package_usd': str(min(prices)),
    'max_package_usd': str(max(prices)),
    'min_usd_per_included_output': str(min(units)),
    'max_usd_per_included_output': str(max(units)),
    'unit_price_max_min_ratio': str(max(units) / min(units)),
    'packages_below_40_usd': sum(p < 40 for p in prices),
}
(ROOT / 'summary.json').write_text(json.dumps(summary, indent=2) + '\n')
print(json.dumps(summary, indent=2))

plt.rcParams.update({'font.family': 'DejaVu Sans', 'font.size': 12, 'svg.fonttype': 'none'})
for key, name, title, subtitle in [
    ('price', 'package-prices', 'AI headshot package prices', '9 individual offers · 3 providers · USD · September 22, 2026'),
    ('unit_price', 'price-per-output', 'Price per included generated image', 'September 22, 2026 · Package price ÷ included outputs · No quality adjustment'),
]:
    ordered = sorted(rows, key=lambda r: (r[key], r['provider'], r['plan']))
    fig, ax = plt.subplots(figsize=(12, 7.5), facecolor='white')
    fig.subplots_adjust(left=0.30, right=0.94, top=0.79, bottom=0.18)
    values = [float(r[key]) for r in ordered]
    labels = [r['provider'] + ' / ' + r['plan'] for r in ordered]
    bars = ax.barh(labels, values, color='#282828', height=0.58)
    ax.invert_yaxis()
    ax.set_xlim(0, max(values) * 1.18)
    ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: f'${x:g}'))
    ax.xaxis.grid(True, color='#dedede', linewidth=0.6)
    ax.set_axisbelow(True)
    ax.tick_params(axis='both', length=0, pad=9, labelsize=11)
    for spine in ax.spines.values():
        spine.set_visible(False)
    for bar, value in zip(bars, values):
        label = f'${value:.0f}' if key == 'price' else f'${value:.2f}'
        ax.text(value + max(values) * 0.02, bar.get_y() + bar.get_height() / 2,
                label, va='center', fontsize=12, fontweight='bold')
    fig.text(0.05, 0.95, 'MORPHED RESEARCH', fontsize=10, fontweight='bold', color='#555555')
    fig.text(0.05, 0.89, title, fontsize=23, fontweight='bold')
    fig.text(0.05, 0.84, subtitle, fontsize=11, color='#555555')
    fig.text(0.05, 0.09, 'Morphed calculations from official HeadshotPro, Aragon and BetterPic pricing pages.', fontsize=10)
    fig.text(0.05, 0.06, 'Observed offers include discounts. Generated outputs are not verified usable headshots.', fontsize=10, color='#555555')
    fig.text(0.05, 0.025, 'morphed.app/blog/ai-headshot-pricing-study', fontsize=10)
    fig.savefig(ROOT / f'{name}.svg', metadata={'Date': None})
    fig.savefig(ROOT / f'{name}.png', dpi=180)
    plt.close(fig)
