#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Render four original A4 inquiry mats as SVG and reproducible PDF."""
from __future__ import annotations

import argparse
import os
import subprocess
from pathlib import Path
from xml.sax.saxutils import escape

HERE = Path(__file__).resolve().parent
INK = "#173b50"


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


def panel(x: float, y: float, w: float, h: float, tint: str) -> str:
    return (f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="2.8" '
            f'fill="{tint}" stroke="{INK}" stroke-width="0.6"/>')


def line(x: float, y: float, end: float) -> str:
    return f'<path d="M{x} {y}H{end}" stroke="#55798a" stroke-width="0.45"/>'


def page(title: str, description: str, parts: list[str]) -> str:
    return f'''<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" viewBox="0 0 210 297" role="img" aria-labelledby="title desc">
<title id="title">{escape(title)}</title><desc id="desc">{escape(description)}</desc>
<rect width="210" height="297" fill="#fffefa"/>
<g font-family="DejaVu Sans, sans-serif" fill="{INK}">{''.join(parts)}</g>
<text x="12" y="289" font-family="DejaVu Sans, sans-serif" font-size="3.1" fill="{INK}">SubjectNest · original Year 11 inquiry aid · CC BY 4.0 · neuroforge.io</text>
</svg>
'''


def source_claim() -> str:
    p = [t(12, 18, "Read the claim; keep the condition", 7.0, True),
         t(12, 27, "A public sentence is made by someone, for someone, from selected facts.", 3.5),
         panel(12, 38, 186, 43, "#eaf3f8"), t(17, 50, "1 · TEXT / MAKER / AUDIENCE", 4.7, True),
         t(17, 62, "Exact word or phrase that positions a reader:", 3.7), line(17, 74, 191),
         panel(12, 91, 186, 43, "#f1edf9"), t(17, 103, "2 · DESK NOTE / MODEL", 4.7, True),
         t(17, 115, "State the unit, base, period or whole-set rule:", 3.7), line(17, 127, 191),
         panel(12, 144, 186, 43, "#edf6ee"), t(17, 156, "3 · WHAT THE NUMBERS SUPPORT", 4.7, True),
         t(17, 168, "Name the group, quantity and known comparison:", 3.7), line(17, 180, 191),
         panel(12, 197, 186, 54, "#fff2e6"), t(17, 209, "4 · REVISE AND KEEP UNKNOWN VISIBLE", 4.5, True),
         t(17, 221, "For this group and model, I can say ...", 3.7), line(17, 233, 191),
         t(17, 243, "Still unknown / next source needed:", 3.7),
         t(12, 270, "Do not turn an invented price or one case into a universal promise.", 3.5)]
    return page("Year 11 source claim mat", "Four numbered reading and drafting spaces: text maker and audience with exact wording; desk-note unit/base/period; supported comparison with named group; revised claim and unknown. The footer says an invented one-case price is not a universal promise. Full text and tactile order in TEXT-ALTERNATIVES.md.", p)


def rate_base() -> str:
    p = [t(12, 18, "Compare like quantities", 7.0, True),
         t(12, 27, "For a whole pack, count packs before multiplying the price.", 3.6),
         panel(12, 38, 186, 48, "#eaf3f8"), t(17, 50, "1 · THE NEED", 4.8, True),
         t(17, 63, "Quantity and unit:", 3.9), line(60, 65, 191),
         t(17, 76, "Can part of a pack be bought? YES / NO / UNKNOWN", 3.7),
         panel(12, 96, 186, 73, "#f1edf9"), t(17, 108, "2 · TWO STATED RULES", 4.8, True),
         t(17, 123, "A: fixed + (per unit × quantity) OR packs × price", 3.5), line(17, 136, 191),
         t(17, 149, "B: fixed + (per unit × quantity) OR packs × price", 3.5), line(17, 162, 191),
         panel(12, 179, 186, 52, "#edf6ee"), t(17, 191, "3 · MATCHED TOTALS", 4.8, True),
         t(17, 204, "A total:             B total:              Known gap:", 3.7), line(17, 217, 191),
         panel(12, 241, 186, 29, "#fff2e6"), t(17, 253, "4 · CONDITION AND MISSING TERM", 4.6, True),
         t(17, 263, "Only at this quantity; delivery/quality may be unknown.", 3.3)]
    return page("Year 11 rate and base mat", "Four numbered areas: needed quantity and whether a pack can be split; two fixed-plus-variable or whole-pack rules; matched totals and gap; a condition and missing term. No colour is required to follow the order. Full text/tactile route in TEXT-ALTERNATIVES.md.", p)


def budget_window() -> str:
    p = [t(12, 18, "What is actually available?", 7.2, True),
         t(12, 27, "Separate an allocation from committed, proposed and unknown amounts.", 3.5),
         panel(12, 39, 186, 50, "#eaf3f8"), t(17, 51, "1 · WINDOW / INCOME", 4.8, True),
         t(17, 65, "One week / four-week what-if / other stated period:", 3.6), line(17, 80, 191),
         panel(12, 99, 186, 69, "#f1edf9"), t(17, 111, "2 · CATEGORIES", 4.8, True),
         t(17, 126, "FIXED or already committed:", 3.8), line(97, 128, 191),
         t(17, 142, "DISCRETIONARY or proposed:", 3.8), line(106, 144, 191),
         t(17, 157, "UNKNOWN is not $0:", 3.8), line(83, 159, 191),
         panel(12, 178, 186, 53, "#edf6ee"), t(17, 190, "3 · REMAINDER", 4.8, True),
         t(17, 204, "Allocation − stated commitments − chosen proposal:", 3.5), line(17, 220, 191),
         panel(12, 241, 186, 29, "#fff2e6"), t(17, 253, "4 · REPEAT ONLY IF ASSUMPTIONS HOLD", 4.2, True),
         t(17, 263, "Name the period; ask what needs a fresh quote.", 3.4)]
    return page("Year 11 budget window mat", "Four numbered areas: period and allocation; fixed, discretionary/proposed and unknown categories; subtraction for remaining amount; repeat condition and next quote. UNKNOWN is not zero. Complete tactile route in TEXT-ALTERNATIVES.md.", p)


def percent_period() -> str:
    p = [t(12, 18, "Name the base. Name the period.", 7.0, True),
         t(12, 27, "Percentages change a stated base; time must match the rate.", 3.7),
         panel(12, 39, 186, 49, "#eaf3f8"), t(17, 51, "1 · FIRST BASE AND OPERATION", 4.7, True),
         t(17, 65, "Base $ / amount:                   rate %:", 3.7), line(17, 79, 191),
         panel(12, 98, 186, 49, "#f1edf9"), t(17, 110, "2 · NEW BASE OR TIME PERIOD", 4.7, True),
         t(17, 124, "New amount / annual years / GST status:", 3.6), line(17, 138, 191),
         panel(12, 157, 186, 58, "#edf6ee"), t(17, 169, "3 · RESULT WITH UNITS", 4.7, True),
         t(17, 182, "Simple interest: P × annual decimal rate × years.", 3.5),
         t(17, 195, "Fully taxable GST model: 10% of exclusive price.", 3.5), line(17, 207, 191),
         panel(12, 225, 186, 45, "#fff2e6"), t(17, 237, "4 · CLAIM BOUNDARY", 4.7, True),
         t(17, 250, "What exactly was assumed? What was not modelled?", 3.5), line(17, 262, 191),
         t(12, 280, "A rate for a year is not a rate for a month.", 3.5)]
    return page("Year 11 percent and period mat", "Four numbered areas: initial base and rate; new base or period including GST status; result with simple-interest or fully taxable GST reminder; claim boundary. Footer distinguishes yearly from monthly rates. Full tactile route in TEXT-ALTERNATIVES.md.", p)


ASSETS = (("source-claim", source_claim), ("rate-base", rate_base),
          ("budget-window", budget_window), ("percent-period", percent_period))


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--output-dir", type=Path, default=HERE)
    args = parser.parse_args()
    args.output_dir.mkdir(parents=True, exist_ok=True)
    env = {**os.environ, "SOURCE_DATE_EPOCH": "1790640000"}
    for stem, maker in ASSETS:
        svg = args.output_dir / f"{stem}.svg"
        svg.write_text(maker(), encoding="utf-8")
        subprocess.run(["rsvg-convert", "-f", "pdf", "-o", str(svg.with_suffix(".pdf")), str(svg)],
                       check=True, env=env)
        print(svg.name, svg.with_suffix(".pdf").name)


if __name__ == "__main__":
    main()
