#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Generate original A4 reading and planning aids; default checks SVG source."""
from __future__ import annotations

import argparse
import subprocess
from html import escape
from pathlib import Path

HERE = Path(__file__).resolve().parent
RIGHTS = "SubjectNest by NeuroForgeIO Pty Ltd · CC BY 4.0 · 2026"


def txt(x: float, y: float, value: str, size: float = 4.2, bold: bool = False) -> str:
    return f'<text x="{x}" y="{y}" font-size="{size}" font-weight="{700 if bold else 400}">{escape(value)}</text>'


def line(x1: float, y1: float, x2: float, y2: float, width: float = .45) -> str:
    return f'<path d="M{x1} {y1} L{x2} {y2}" fill="none" stroke="black" stroke-width="{width}"/>'


def box(x: float, y: float, w: float, h: float) -> str:
    return f'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="white" stroke="black" stroke-width=".6"/>'


def page(title: str, desc: str, body: list[str]) -> str:
    return "\n".join([
        '<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" viewBox="0 0 210 297" role="img" aria-labelledby="title desc">',
        f'<title id="title">{escape(title)}</title>',
        f'<desc id="desc">{escape(desc)}</desc>',
        '<rect width="210" height="297" fill="white"/>',
        '<g fill="black" font-family="DejaVu Sans, sans-serif">',
        *body,
        line(12, 281, 198, 281), txt(12, 289, RIGHTS, 2.9),
        '</g>', '</svg>', ''
    ])


def repair_poster() -> str:
    body = [
        txt(13, 21, 'DOCKSIDE FIX CLUB', 7.2, True),
        txt(13, 32, 'Fictional classroom poster · 18 September 2026', 3.8),
        line(13, 38, 197, 38, 1),
        txt(13, 77, 'ELEVEN', 25, True),
        txt(13, 94, 'WORKING BY CLOSING TIME!', 8.6, True),
        line(13, 103, 197, 103, 1),
        txt(13, 124, 'A small trial checked 18 brought-in items.', 4.7),
        txt(13, 136, 'Eleven were working when the table closed.', 4.7),
        txt(13, 155, 'If another session is approved, ask the organiser', 4.4),
        txt(13, 166, 'about the date and suitable items.', 4.4),
        box(13, 200, 184, 55),
        txt(18, 212, 'Read the closing detail too', 4.2, True),
        txt(18, 224, 'Four items were waiting for parts;', 3.9),
        txt(18, 234, 'three were not repaired at closing.', 3.9),
        txt(18, 244, 'This count does not say how long any repair lasted', 3.35),
        txt(18, 252, 'or what another session would cost.', 3.35),
        txt(13, 267, 'Invented source A · created by the same club as its closing tally', 3.2),
    ]
    return page('Fictional Dockside Fix Club poster',
                'Original black-on-white fictional poster. ELEVEN is the largest word near the upper middle. WORKING BY CLOSING TIME follows in bold. In regular text the poster says 18 items were checked and eleven worked at closing. A small boxed line near the bottom says four waited for parts, three were not repaired, and durability and cost are unknown. The full exact text and reading order are supplied in TEXT-ALTERNATIVES.md.', body)


def source_comparison() -> str:
    body = [
        txt(12, 19, 'Compare two sources about one event', 6.6, True),
        txt(12, 30, 'Record what each source says. Then ask what both still leave open.', 3.8),
        box(12, 38, 90, 214), box(108, 38, 90, 214),
    ]
    fields = [('Source ID / text type', 49, 57),
              ('Creator / date', 78, 86),
              ('Audience / purpose', 107, 115),
              ('Exact claim or detail', 136, 144),
              ('What the source cannot show', 178, 186),
              ('One question to ask next', 218, 226)]
    for label, heading_y, rule_y in fields:
        for x in (17, 113):
            body.append(txt(x, heading_y, label, 3.3, True))
            body.append(line(x, rule_y + 10, x + 79, rule_y + 10))
            if label in ('Exact claim or detail', 'What the source cannot show'):
                body.append(line(x, rule_y + 21, x + 79, rule_y + 21))
    body += [txt(12, 263, 'Shared origin?  [  ] same creator/event   [  ] different   [  ] unknown', 3.8),
             txt(12, 274, 'Similar wording alone does not prove independent confirmation.', 3.55)]
    return page('Year 6 English · two-source comparison mat',
                'A blank A4 two-column comparison mat. Each source column has identical writing fields: source ID and text type, creator and date, audience and purpose, exact claim or detail, what the source cannot show, and one question to ask next. A footer asks whether the sources share a creator or event. No answer is filled in.', body)


def argument_planner() -> str:
    body = [txt(12, 19, 'A careful argument for a real reader', 6.5, True),
            txt(12, 30, 'Name the decision and audience. Link evidence to a source ID.', 3.9),
            txt(12, 42, 'Reader / decision:', 4.1, True), line(52, 44, 197, 44)]
    stages = [
        (51, '1  RECOMMENDATION', 'What should the reader consider, and under what condition?'),
        (99, '2  EXACT EVIDENCE', 'What did a named source actually record or say?'),
        (147, '3  LIMIT OR COUNTERPOINT', 'What is not shown? Which different view matters?'),
        (195, '4  CAREFUL NEXT STEP', 'What could a small test or new question find out?'),
    ]
    for y, heading, prompt in stages:
        body += [box(12, y, 186, 43), txt(17, y + 9, heading, 4.4, True),
                 txt(17, y + 18, prompt, 3.35),
                 line(17, y + 29, 193, y + 29), line(17, y + 38, 193, y + 38)]
    body += [txt(12, 251, 'Source ID(s):', 4.1, True), line(42, 253, 197, 253),
             txt(12, 266, 'Check: [  ] exact  [  ] conditional  [  ] fair to other views  [  ] revised', 3.6),
             txt(12, 275, 'The stages may be reordered if the reader can still follow each job.', 3.35)]
    return page('Year 6 English · bounded argument planner',
                'Blank A4 argument planner with reader and decision field, then four stacked writing panels: recommendation with condition, exact evidence with source, limit or counterpoint, and careful next step. A source-ID line and four-part revision checklist sit below. No model response or check answer is supplied.', body)


PAGES = {"repair-poster": repair_poster, "source-comparison": source_comparison,
         "argument-planner": argument_planner}


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--write", action="store_true")
    args = parser.parse_args()
    for name, make in PAGES.items():
        svg = HERE / f"{name}.svg"
        expected = make().encode("utf-8")
        if args.write:
            svg.write_bytes(expected)
            subprocess.run(["rsvg-convert", "-f", "pdf", "-o", str(svg.with_suffix('.pdf')), str(svg)], check=True)
        elif not svg.is_file() or svg.read_bytes() != expected:
            raise SystemExit(f"FAIL: {svg.name} missing or changed; review and use --write")
    print("PASS: three original A4 SVG aids" + (" and PDF exports" if args.write else " match drawing source"))


if __name__ == "__main__":
    main()
