#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Original A4 Year 7 maths aids; default checks checked-in SVGs read-only."""
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.0, 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 path(d: str, width: float = .45) -> str:
    return f'<path d="{d}" 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">',
        txt(12, 20, title, 6.3, True), path('M12 26 L198 26'), *body,
        path('M12 281 L198 281'), txt(12, 289, RIGHTS, 2.8),
        '</g>', '</svg>', ''
    ])


def operation_check() -> str:
    body = [txt(12, 37, 'Name the WHOLE and UNIT before choosing an operation.', 4, True),
            txt(12, 49, 'Situation / question:', 4.1, True), path('M12 59 L198 59'),
            txt(12, 73, '1  Estimate a useful range', 4.4, True),
            box(12, 80, 186, 36), txt(17, 92, 'My estimate and why it is sensible:', 3.7),
            path('M17 105 L193 105'),
            txt(12, 130, '2  Model or choose an operation', 4.4, True),
            box(12, 137, 186, 42), txt(17, 149, 'Same whole? Matching units? Show a diagram or equation.', 3.35),
            path('M17 161 L193 161'), path('M17 173 L193 173'),
            txt(12, 192, '3  Exact result with unit', 4.4, True),
            box(12, 199, 186, 28), path('M17 219 L193 219'),
            txt(12, 241, '4  Check by inverse or benchmark', 4.4, True),
            box(12, 248, 186, 27), path('M17 267 L193 267')]
    return page('Year 7 maths · operation and check mat',
                'A blank four-stage A4 mat. In vertical reading order: situation/question line; estimate and reason box; model/operation box with same-whole and matching-unit prompt; exact result/unit box; inverse-or-benchmark check box. No operation or answer is pre-filled.', body)


def prime_factor_tree() -> str:
    body = [txt(12, 36, 'Split a natural number until EVERY final leaf is PRIME.', 4, True),
            box(84, 44, 42, 16), txt(90, 55, 'Start N: ______', 3.7)]
    levels = [(1, 74, 42), (2, 112, 34), (3, 150, 20)]
    for count, y, w in levels:
        total = 2**count
        space = 184 / total
        for i in range(total):
            x = 13 + i * space + (space - w) / 2
            body.append(box(x, y, w, 14))
            if count == 1:
                parent = 105
                py = 60
            else:
                parent_count = 2 ** (count - 1)
                pspace = 184 / parent_count
                parent = 13 + (i // 2) * pspace + pspace / 2
                py = levels[count - 2][1] + 14
            body.append(path(f'M{parent} {py} L{x + w / 2} {y}'))
    body += [txt(12, 180, 'Use only the leaves you need; leave unused branches blank.', 3.65),
             txt(12, 199, 'Prime leaves in order:', 4.2, True), path('M69 201 L198 201'),
             txt(12, 219, 'Product with exponents:', 4.2, True), path('M82 221 L198 221'),
             txt(12, 239, 'Multiply back to check N:', 4.2, True), path('M90 241 L198 241'),
             txt(12, 260, 'If a leaf is composite, split it again on another line.', 3.65)]
    return page('Year 7 maths · blank prime-factor tree',
                'Blank top start box, then two, four and eight successively lower branch boxes connected as a tree. Learners use as many branches as needed; leaves must be prime. Three blank lines below request ordered prime leaves, exponent product and multiplication-back. No number or factor is filled in.', body)


def square_root_link() -> str:
    body = [txt(12, 36, 'A square has equal side counts. Test a root by squaring it.', 3.9, True),
            txt(12, 49, 'Side length = ______ cells', 4.1),
            txt(114, 49, 'Area = ______ cells', 4.1)]
    x0, y0, cell = 37, 59, 8.0
    for step in range(13):
        x = x0 + step * cell
        y = y0 + step * cell
        body += [path(f'M{x} {y0} L{x} {y0 + 12 * cell}', .35),
                 path(f'M{x0} {y} L{x0 + 12 * cell} {y}', .35)]
    body += [txt(12, 176, 'Side × side = square total:', 4.1, True), path('M92 178 L198 178'),
             txt(12, 194, 'Positive square root of total:', 4.1, True), path('M113 196 L198 196'),
             txt(12, 212, 'Prime factors of the side:', 4.1, True), path('M91 214 L198 214'),
             txt(12, 230, 'Prime factors of the area:', 4.1, True), path('M91 232 L198 232'),
             txt(12, 250, 'Check: root × root = area', 3.9, True), path('M12 262 L198 262'),
             txt(12, 274, 'The grid has 12 by 12 blank cells; use any smaller square too.', 3.3)]
    return page('Year 7 maths · square and positive root link',
                'Blank 12 by 12 cell grid on A4. It supports a square array up to 12 by 12 but no cells are shaded. Blank prompts below connect side times side, positive square root, prime factors of side and area, and multiplication-back. No checked answer or Day 20 number is printed.', body)


PAGES = {"operation-check": operation_check,
         "prime-factor-tree": prime_factor_tree,
         "square-root-link": square_root_link}


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()
