#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Original Year 4 decimal-line and equal-whole A4 aids.

Default is a read-only comparison of checked-in SVGs. --write deliberately
regenerates SVGs and searchable PDF exports using rsvg-convert.
"""
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 path(d: str, width: float = 0.6) -> str:
    return f'<path d="{d}" fill="none" stroke="black" stroke-width="{width}"/>'


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, 7, True), path('M12 25 L198 25'),
        *body,
        path('M12 282 L198 282'), txt(12, 289, RIGHTS, 2.8),
        '</g>', '</svg>', ''
    ])


def ruled_line(y: float, left: str, right: str) -> list[str]:
    marks = [path(f'M20 {y} L190 {y}', 0.9)]
    for step in range(11):
        x = 20 + step * 17
        marks.append(path(f'M{x} {y - 5} L{x} {y + 5}', 0.8 if step in (0, 10) else 0.55))
    marks += [txt(18, y + 14, left, 4.2, True), txt(181, y + 14, right, 4.2, True)]
    return marks


def decimal_line() -> str:
    body = [txt(12, 35, 'Count equal SPACES after the left endpoint. Mark a point and say why.', 3.9, True),
            txt(12, 51, 'A · one whole split into ten tenths', 4.2, True),
            *ruled_line(68, '0', '1'),
            txt(12, 94, 'My mark is ______ ; it is ______ spaces after ______.', 3.8),
            txt(12, 113, 'B · zoom one tenth into ten hundredths', 4.2, True),
            *ruled_line(130, '0.20', '0.30'),
            txt(12, 156, 'Each gap = 0.01. My mark is ______ ; I counted ______ gaps.', 3.8),
            txt(12, 176, 'C · zoom beyond one whole', 4.2, True),
            *ruled_line(193, '1.00', '1.10'),
            txt(12, 219, 'My mark is ______ ; its whole/tenth/hundredth places are __________.', 3.5),
            txt(12, 243, 'Scale check: are all the spaces on this line equal? [ ] yes [ ] redo', 3.7),
            txt(12, 257, 'If your lesson uses different endpoints, relabel a blank line first.', 3.7),
            txt(12, 269, 'A point on one zoom is not automatically at the same place on another.', 3.4)]
    return page('Year 4 maths · three decimal number lines', 'Three original blank horizontal lines. Each line has 11 tick positions and 10 equal spaces. Line A endpoints are 0 and 1, with a gap of 0.1; line B endpoints 0.20 and 0.30, gap 0.01; line C endpoints 1.00 and 1.10, gap 0.01. Recording prompts ask the learner to name a point, count gaps and check scale. No interior answer is marked.', body)


def square(x: float, y: float, parts: int, label: str) -> list[str]:
    size = 72
    lines = [txt(x, y - 4, label, 3.9, True), path(f'M{x} {y} H{x + size} V{y + size} H{x} Z', 0.75)]
    for step in range(1, parts):
        mark = y + step * size / parts
        lines.append(path(f'M{x} {mark} H{x + size}', 0.55))
    return lines


def equal_whole() -> str:
    body = [txt(12, 34, 'All FIVE squares are the SAME SIZE whole. Shade matching shares.', 3.8, True)]
    body += square(20, 44, 2, '2 equal parts')
    body += square(118, 44, 4, '4 equal parts')
    body += square(20, 125, 5, '5 equal parts')
    body += square(118, 125, 10, '10 equal parts')
    body += [txt(20, 202, '100 equal cells', 3.9, True)]
    x0, y0, cell = 20, 206, 7.2
    body.append(path(f'M{x0} {y0} H{x0 + cell * 10} V{y0 + cell * 10} H{x0} Z', 0.75))
    for step in range(1, 10):
        x = x0 + step * cell
        y = y0 + step * cell
        body += [path(f'M{x} {y0} V{y0 + cell * 10}', 0.35), path(f'M{x0} {y} H{x0 + cell * 10}', 0.35)]
    body += [txt(118, 216, 'My fraction names:', 4.1, True),
             txt(118, 231, '_____ / _____', 4.0),
             txt(118, 244, '= _____ / _____', 4.0),
             txt(118, 257, '= __________ decimal', 3.7),
             txt(118, 272, 'Why equal? __________', 3.5)]
    return page('Year 4 maths · equal whole equivalence mat', 'Five equal-sized 72 by 72 millimetre blank square wholes arranged in two columns. They are divided respectively into 2, 4, 5, 10 horizontal equal parts and a 10 by 10 grid of 100 equal square cells. Learners shade matching shares and complete blank fraction, decimal and explanation lines. No part is shaded and no answer is supplied.', body)


PAGES = {"decimal-line": decimal_line, "equal-whole": equal_whole}


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: two original A4 SVG aids" + (" and PDF exports" if args.write else " match drawing source"))


if __name__ == "__main__":
    main()
