#!/usr/bin/env python3
"""Make three original A4 SVG/PDF Year 8 algebra aids using rsvg-convert."""

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, BLUE, MUTED = "#17212b", "#145d78", "#425669"


def txt(x: int, y: int, s: str, size: int = 19, weight: int = 400,
        colour: str = INK, anchor: str = "start") -> str:
    return (f'<text x="{x}" y="{y}" fill="{colour}" font-family="DejaVu Sans, sans-serif" '
            f'font-size="{size}" font-weight="{weight}" text-anchor="{anchor}">{escape(s)}</text>')


def box(x: int, y: int, w: int, h: int, fill: str = "white", stroke: str = INK,
        rad: int = 9, sw: int = 2) -> str:
    return (f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{rad}" '
            f'fill="{fill}" stroke="{stroke}" stroke-width="{sw}"/>')


def line(x1: int, y1: int, x2: int, y2: int, sw: int = 2, colour: str = INK) -> str:
    return f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{colour}" stroke-width="{sw}"/>'


def page(title: str, desc: str, middle: list[str], footer: str) -> str:
    head = ['<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" viewBox="0 0 794 1123" role="img">',
            f'<title>{escape(title)}</title>', f'<desc>{escape(desc)}</desc>',
            '<rect width="794" height="1123" fill="white"/>',
            box(34, 27, 726, 98, fill="#e9f3f6", stroke=BLUE),
            txt(53, 64, "SUBJECTNEST / YEAR 8 / MATHEMATICS", 16, 700, BLUE),
            txt(53, 104, title, 29, 700)]
    tail = [line(34, 1074, 760, 1074, colour=MUTED),
            txt(40, 1100, footer, 13, colour=MUTED), '</svg>']
    return "\n".join(head + middle + tail) + "\n"


def expression_tiles() -> str:
    a = [txt(40, 162, "MODEL: three equal groups of x + 4", 20, 700),
         txt(40, 193, "The x tile stands for a variable count, not one card.", 16),
         txt(40, 230, "Each row is one complete bracket.", 16, colour=MUTED)]
    for i in range(3):
        y = 257 + 168 * i
        a += [box(40, y, 714, 142),
              box(56, y + 38, 167, 69, fill="#e9f3f6", stroke=BLUE),
              txt(139, y + 83, "x", 32, 700, BLUE, "middle"),
              txt(238, y + 82, "+", 29, 700)]
        for j in range(4):
            xx = 279 + 102 * j
            a += [box(xx, y + 41, 75, 65), txt(xx + 37, y + 83, "1", 25, 700, anchor="middle")]
        a.append(txt(679, y + 81, f"row {i + 1}", 14, colour=MUTED))
    a += [box(40, 785, 714, 244, fill="#fafcfd", stroke=BLUE),
          txt(57, 820, "COUNT IN TWO WAYS", 19, 700, BLUE),
          txt(57, 861, "Grouped: 3(x + 4)", 19),
          txt(57, 901, "Expanded: x + x + x + 4 + 4 + 4 = 3x + 12", 19),
          txt(57, 944, "Try another input: x = _______", 18),
          txt(57, 987, "Both forms give _______ because ____________________", 17)]
    return page("Expression grouping board",
                "Three large rows each contain one x-labelled variable tile and four unit tiles. The words below count 3(x+4) as x+x+x+4+4+4=3x+12. A blank substitution line supports checking another value.",
                a, "Original A4 grouping model · use text/tactile alternative alongside")


def balance() -> str:
    a = [txt(40, 163, "Every equality step acts on BOTH sides.", 20, 700),
         txt(40, 195, "An equation can be solved; a model also needs a valid domain.", 17),
         box(40, 224, 714, 161, fill="#fafcfd", stroke=BLUE),
         txt(60, 261, "Original relation:", 18, 700, BLUE),
         txt(60, 306, "Left side: __________________  =  Right side: _______________", 18),
         txt(60, 351, "Variable and allowed values: _____________________________", 17),
         txt(40, 430, "WRITE EACH BALANCED MOVE", 19, 700)]
    heads = [(60, "Operation on both sides"), (425, "New equality / reason")]
    a += [box(40, 447, 714, 60, fill="#e9f3f6", stroke=BLUE)]
    a += [txt(x, 483, s, 17, 700, BLUE) for x, s in heads]
    for i in range(4):
        y = 507 + i * 112
        a += [box(40, y, 714, 112), line(404, y, 404, y + 112, colour=MUTED),
              txt(59, y + 43, f"{i + 1}. ______________________", 18),
              txt(422, y + 43, "________________________", 18),
              txt(59, y + 83, "________________________", 18),
              txt(422, y + 83, "________________________", 18)]
    a += [box(40, 971, 714, 83, fill="#fafcfd", stroke=BLUE),
          txt(58, 1004, "CHECK: substitute input ______ into the ORIGINAL.", 17, 700),
          txt(58, 1036, "Left ______    Right ______    In the model? ______", 17)]
    return page("Balance + rearrange mat",
                "A blank A4 equation board. Top fields name original left and right sides, variable and allowed values. Four rows have two columns: operation on both sides and new equality or reason. Bottom fields ask to substitute into the original and check model domain.",
                a, "Original A4 equation scaffold · full text/tactile route alongside")


def graph() -> str:
    a = [txt(40, 162, "Label axes and units before plotting.", 20, 700),
         txt(40, 191, "Whole-number inputs are the actual batch/poster cases here.", 16)]
    x0, x1, y0, y1 = 124, 718, 750, 270
    a += [box(40, 218, 714, 608), txt(60, 254, "CARTESIAN GRID: relation / cap / crossing", 17, 700, BLUE),
          line(x0, y0, x1, y0, sw=3), line(x0, y0, x0, y1, sw=3)]
    # x = 0..8 in whole units; y = 0..40 in increments of 5.
    for i in range(9):
        x = x0 + i * 70
        a += [line(x, y0, x, y1, sw=1, colour="#b8c8d0"),
              txt(x, y0 + 29, str(i), 15, anchor="middle")]
    for i in range(9):
        y = y0 - i * 57
        a += [line(x0, y, x1, y, sw=1, colour="#b8c8d0"),
              txt(x0 - 16, y + 6, str(5 * i), 15, anchor="end")]
    a += [txt(410, 813, "input (batches/posters/turns)", 16, anchor="middle"),
          txt(50, 377, "model", 16), txt(50, 400, "total", 16),
          box(40, 850, 714, 202), txt(57, 883, "NUMBER LINE: mark allowed values", 18, 700, BLUE),
          line(91, 955, 706, 955, sw=3)]
    for i in range(11):
        x = 91 + i * 61
        a += [line(x, 944, x, 966, sw=2), txt(x, 990, str(i), 15, anchor="middle")]
    a += [txt(57, 1028, "Closed dot includes boundary. Open dot excludes it.", 16)]
    return page("Line + boundary board",
                "A blank Cartesian grid with x-input ticks 0 through 8 and y-total ticks 0 through 40 by fives, followed by a blank number line 0 through 10. Text says whole-number inputs are the available model cases and explains closed/open boundary dots.",
                a, "Original A4 graph scaffold · read every tick aloud if needed")


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--write", action="store_true")
    args = parser.parse_args()
    if not args.write:
        parser.error("pass --write to regenerate the three aid pairs")
    for stem, builder in (("expression-tiles", expression_tiles),
                          ("balance-rearrange", balance),
                          ("line-and-boundary", graph)):
        svg = HERE / f"{stem}.svg"
        pdf = HERE / f"{stem}.pdf"
        svg.write_text(builder(), encoding="utf-8")
        # Cairo honours SOURCE_DATE_EPOCH, keeping PDF metadata/bytes reproducible.
        env = {**os.environ, "SOURCE_DATE_EPOCH": "1790640000"}  # 2026-09-29 00:00 UTC.
        subprocess.run(["rsvg-convert", "--format", "pdf", "--output", str(pdf), str(svg)],
                       check=True, env=env)
        print(f"generated {svg.name} + {pdf.name}")


if __name__ == "__main__":
    main()
