#!/usr/bin/env python3
"""Rebuild responsive, accessible SVG redraws from the linked digitized CSV."""
from pathlib import Path
import csv
import html
import xml.etree.ElementTree as ET

ROOT = Path(__file__).resolve().parent
CSV_PATH = ROOT / "nasa-2011-figure5-digitized.csv"
DATA = list(csv.DictReader(CSV_PATH.open(encoding="utf-8", newline="")))
NAVY = "#142f4b"
PINK = "#c72c83"
GRID = "#d9e3ed"
INK = "#14253a"
MUTED = "#51677e"


def esc(s):
    return html.escape(str(s), quote=True)


def make_svg(mobile=False):
    w, h = (760, 760) if mobile else (1200, 650)
    left, right = (92, 725) if mobile else (100, 1140)
    top, bottom = (185, 500) if mobile else (145, 480)
    x = lambda m: left + (right-left) * (float(m)-3.25) / (7.0-3.25)
    y = lambda p: bottom - (bottom-top) * float(p) / 100.0
    title_size = 26 if mobile else 32
    bits = [f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {w} {h}" role="img" aria-labelledby="title desc">',
            '<title id="title">NASA 2011 Figure 5, redrawn from approximate pixel readings</title>',
            '<desc id="desc">A redrawn plot of the report’s modeled extracted power from ambient Mach 3.25 to 7.00. Approximate digitized values rise from about 47 megawatts, peak near 88 megawatts around Mach 5.25, fall to about 52 megawatts around Mach 6, then rise toward 75 megawatts by Mach 6.75. Four highlighted points have a plus or minus 2 megawatt visual reading allowance; it is not model uncertainty.</desc>',
            f'<rect width="{w}" height="{h}" rx="24" fill="#f7faff"/>',
            f'<text x="36" y="48" font-family="Arial,sans-serif" font-size="{title_size}" font-weight="700" fill="{INK}">A published model curve, read point by point</text>',
            f'<text x="36" y="82" font-family="Arial,sans-serif" font-size="17" fill="{MUTED}">NASA/TM-2011-217136 · Figure 5 · approximate digitization, not NPSS output data</text>']
    for power in range(0, 101, 20):
        yy = y(power)
        bits.append(f'<line x1="{left}" y1="{yy:.1f}" x2="{right}" y2="{yy:.1f}" stroke="{GRID}" stroke-width="2"/>')
        bits.append(f'<text x="{left-12}" y="{yy+5:.1f}" text-anchor="end" font-family="Arial,sans-serif" font-size="15" fill="{MUTED}">{power}</text>')
    ticks = [3.25, 3.75, 4.25, 4.75, 5.25, 5.75, 6.25, 6.75, 7.00]
    for mach in ticks:
        xx = x(mach)
        bits.append(f'<line x1="{xx:.1f}" y1="{top}" x2="{xx:.1f}" y2="{bottom}" stroke="{GRID}" stroke-width="1"/>')
        bits.append(f'<text x="{xx:.1f}" y="{bottom+27}" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" fill="{MUTED}">{mach:.2f}</text>')
    poly = " ".join(f'{x(r["ambient_mach_approx"]):.2f},{y(r["curve_centerline_power_MW_approx"]):.2f}' for r in DATA)
    bits.append(f'<polyline points="{poly}" fill="none" stroke="{PINK}" stroke-width="4" stroke-linejoin="round" stroke-linecap="round"/>')
    highlights = {4.75: 69.86, 5.25: 87.67, 6.00: 52.40, 6.75: 75.34}
    for mach, power in highlights.items():
        xx, yy = x(mach), y(power)
        err = (bottom-top) * 2.0 / 100.0
        bits.append(f'<line x1="{xx:.2f}" y1="{yy-err:.2f}" x2="{xx:.2f}" y2="{yy+err:.2f}" stroke="{NAVY}" stroke-width="3"/><line x1="{xx-7:.2f}" y1="{yy-err:.2f}" x2="{xx+7:.2f}" y2="{yy-err:.2f}" stroke="{NAVY}" stroke-width="3"/><line x1="{xx-7:.2f}" y1="{yy+err:.2f}" x2="{xx+7:.2f}" y2="{yy+err:.2f}" stroke="{NAVY}" stroke-width="3"/><circle cx="{xx:.2f}" cy="{yy:.2f}" r="7" fill="{PINK}" stroke="white" stroke-width="2"/>')
    bits.append(f'<line x1="{left}" y1="{top}" x2="{left}" y2="{bottom}" stroke="{NAVY}" stroke-width="2"/><line x1="{left}" y1="{bottom}" x2="{right}" y2="{bottom}" stroke="{NAVY}" stroke-width="2"/>')
    bits.append(f'<text x="{(left+right)/2:.1f}" y="{bottom+58}" text-anchor="middle" font-family="Arial,sans-serif" font-size="17" fill="{INK}">Ambient Mach number</text>')
    bits.append(f'<text transform="translate(27 {(top+bottom)/2:.1f}) rotate(-90)" text-anchor="middle" font-family="Arial,sans-serif" font-size="17" fill="{INK}">Extracted electrical power (MW)</text>')
    if mobile:
        note_y = 620
        bits.append(f'<text x="36" y="{note_y}" font-family="Arial,sans-serif" font-size="14" fill="{MUTED}">Whiskers at four points: about ±2 MW of visual reading only.</text>')
        bits.append(f'<text x="36" y="{note_y+24}" font-family="Arial,sans-serif" font-size="14" fill="{MUTED}">They are not statistical or model uncertainty.</text>')
        bits.append(f'<text x="36" y="{note_y+48}" font-family="Arial,sans-serif" font-size="14" fill="{MUTED}">The curve is a model prediction, not measured data.</text>')
    else:
        bits.append(f'<text x="100" y="560" font-family="Arial,sans-serif" font-size="16" fill="{MUTED}">Highlighted point whiskers: ≈±2 MW visual allowance only · no raw NPSS point table was supplied</text>')
        bits.append(f'<text x="100" y="588" font-family="Arial,sans-serif" font-size="16" fill="{MUTED}">Figure readings are approximate and are not measurements or a confidence interval.</text>')
    bits.append('</svg>')
    return '\n'.join(bits) + '\n'


def main():
    if len(DATA) != 76:
        raise SystemExit(f"Expected 76 source readings, got {len(DATA)}")
    for mobile in (False, True):
        suffix = "-mobile" if mobile else ""
        name = ROOT / f"nasa-2011-figure5-redraw{suffix}.svg"
        name.write_text(make_svg(mobile), encoding="utf-8")
        ET.parse(name)
    print("Generated and parsed the desktop and mobile NASA Figure 5 redraws from 76 linked readings.")


if __name__ == "__main__":
    main()
