# SPDX-License-Identifier: Apache-2.0
"""Generate original selectable-text A4 Foundation maths print aids."""

from __future__ import annotations

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

HERE = Path(__file__).resolve().parent
INK = "#18364a"
BLUE = "#eaf4f8"
GREEN = "#eef7ec"
PEACH = "#fff0e4"


def box(
    x: int,
    y: int,
    width: int,
    height: int,
    fill: str = "white",
) -> str:
    """Return one labelled-area rectangle."""
    return (
        f'<rect x="{x}" y="{y}" width="{width}" height="{height}" '
        f'rx="12" fill="{fill}" stroke="{INK}" stroke-width="2"/>'
    )


def sharp_box(x: int, y: int, width: int, height: int, fill: str = "white") -> str:
    """Return a square-cornered rectangle for cutouts and geometric shapes."""
    return box(x, y, width, height, fill).replace('rx="12"', 'rx="0"')


def word(x: int, y: int, value: str, size: int = 20, weight: int = 400) -> str:
    """Return selectable SVG text."""
    return (
        f'<text x="{x}" y="{y}" fill="{INK}" font-family="DejaVu Sans" '
        f'font-size="{size}" font-weight="{weight}">{escape(value)}</text>'
    )


def line(x1: int, y1: int, x2: int, y2: int, width: int = 2) -> str:
    """Return a dark straight line."""
    return (
        f'<path d="M{x1} {y1} L{x2} {y2}" fill="none" '
        f'stroke="{INK}" stroke-width="{width}"/>'
    )


def page(title: str, description: str, body: str) -> str:
    """Wrap original content in a physical A4 page."""
    footer = "SubjectNest · original Foundation maths aid · CC BY 4.0"
    return (
        '<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" '
        'viewBox="0 0 794 1123" role="img">'
        f"<title>{escape(title)}</title><desc>{escape(description)}</desc>"
        '<rect width="794" height="1123" fill="#ffffff"/>'
        f"{word(45, 70, title, 27, 700)}"
        f"{word(45, 105, description, 13)}"
        f"{body}{line(45, 1052, 749, 1052)}"
        f"{word(45, 1080, footer, 11)}"
        "</svg>\n"
    )


def share_mat() -> str:
    """Make reusable recipient and equal-group workspaces."""
    body = word(45, 155, "Equal share: one like piece per tray in turn.", 18, 700)
    body += box(45, 188, 330, 310, BLUE)
    body += box(419, 188, 330, 310, GREEN)
    body += word(70, 235, "TRAY A", 23, 700)
    body += word(445, 235, "TRAY B", 23, 700)
    body += word(70, 462, "Count: ____", 17)
    body += word(445, 462, "Count: ____", 17)
    body += word(45, 545, "Equal groups: how many in each? how many groups?", 18, 700)
    for i in range(3):
        x = 45 + i * 239
        body += box(x, 580, 225, 260, PEACH if i % 2 == 0 else BLUE)
        body += word(x + 20, 626, f"GROUP {i + 1}", 19, 700)
        body += word(x + 20, 803, "Cards: ____", 15)
    body += box(45, 875, 704, 120, "white")
    body += word(70, 918, "Same number in each tray or each group? Show why.", 16)
    body += word(70, 957, "Adult may move pieces exactly where child directs.", 15)
    return page(
        "Share fairly on paper; make equal groups",
        "Large spaces for broad cards. Equality is a count, not a social verdict.",
        body,
    )


def room_mat() -> str:
    """Make a stable, unambiguous familiar room model."""
    body = word(
        45, 155, "Keep the three named landmarks fixed while placing groups.", 17, 700
    )
    body += box(45, 190, 704, 675, "white")
    body += box(80, 250, 180, 150, BLUE)
    body += box(535, 250, 180, 150, BLUE)
    body += word(110, 336, "DESK A", 21, 700)
    body += word(562, 336, "DESK B", 21, 700)
    body += box(285, 466, 224, 130, PEACH)
    body += word(307, 539, "GROUP AREA 1", 16, 700)
    body += box(80, 650, 200, 146, GREEN)
    body += word(107, 735, "PUPPET", 22, 700)
    body += box(355, 650, 295, 146, "white")
    body += word(380, 731, "GROUP AREA 2", 18, 700)
    body += box(45, 895, 704, 100, PEACH)
    body += word(68, 936, "Where is the group? Name the landmark(s).", 17)
    body += word(68, 968, "No child movement or left/right guessing required.", 14)
    return page(
        "A familiar paper room: fixed landmarks",
        "Describe each group's location relative to fixed landmarks.",
        body,
    )


def repeat_mat() -> str:
    """Make a neutral repeat strip with room for a whole unit."""
    body = word(
        45, 157, "Copy the given strip. Box one WHOLE part that repeats.", 18, 700
    )
    body += box(45, 200, 704, 335, BLUE)
    body += word(70, 244, "GIVEN / COPIED STRIP", 20, 700)
    for i in range(6):
        x = 65 + i * 112
        body += sharp_box(x, 300, 100, 145, "white")
        body += word(x + 32, 481, str(i + 1), 14, 700)
    body += box(45, 563, 704, 235, GREEN)
    body += word(70, 606, "WHAT COMES NEXT?", 20, 700)
    for i in range(3):
        x = 75 + i * 215
        body += sharp_box(x, 643, 185, 100, "white")
    body += box(45, 825, 704, 170, PEACH)
    body += word(70, 868, "My repeating part is: ______________________", 18)
    body += word(70, 915, "I know because this same part starts again.", 17)
    body += word(70, 960, "Use marks, shapes, words, touch or an adult mover.", 14)
    return page(
        "Find the whole repeating part",
        "Six given places, three next places and a place to name the unit.",
        body,
    )


def shape_icon(kind: str, x: int, y: int) -> str:
    """Draw one familiar shape using geometry rather than colour."""
    if kind == "circle":
        return (
            f'<circle cx="{x}" cy="{y}" r="55" fill="{GREEN}" '
            f'stroke="{INK}" stroke-width="4"/>'
        )
    if kind == "triangle":
        points = f"{x},{y - 64} {x - 65},{y + 55} {x + 65},{y + 55}"
        return (
            f'<polygon points="{points}" fill="{GREEN}" '
            f'stroke="{INK}" stroke-width="4"/>'
        )
    if kind == "square":
        return sharp_box(x - 55, y - 55, 110, 110, GREEN).replace(
            'stroke-width="2"', 'stroke-width="4"'
        )
    if kind == "rectangle":
        return sharp_box(x - 72, y - 42, 144, 84, GREEN).replace(
            'stroke-width="2"', 'stroke-width="4"'
        )
    raise ValueError(kind)


def shape_reason() -> str:
    """Draw an original fictional toy place for feature-based shape names."""
    body = word(
        45, 156, "Fictional toy place: trace a boundary to give a reason.", 17, 700
    )
    body += box(45, 190, 704, 650, BLUE)
    body += (
        f'<polygon points="145,420 397,235 649,420" fill="{PEACH}" '
        f'stroke="{INK}" stroke-width="5"/>'
    )
    body += sharp_box(145, 420, 504, 360, "white")
    body += (
        f'<circle cx="316" cy="555" r="65" fill="{GREEN}" '
        f'stroke="{INK}" stroke-width="5"/>'
    )
    body += sharp_box(489, 560, 117, 220, PEACH)
    body += word(170, 818, "ROOF: straight sides?", 16)
    body += word(430, 818, "WINDOW: curved edge?", 16)
    body += word(
        45, 876, "Border: TRIANGLE · CIRCLE · TRIANGLE · CIRCLE · ____", 16, 700
    )
    body += box(45, 910, 704, 88, GREEN)
    body += word(68, 949, "Make one matching broad shape; tell why it matches.", 16)
    body += word(68, 978, "No real building is represented or inspected.", 13)
    return page(
        "Find a shape and give a reason",
        "Original pretend toy-place roof, window and door shapes.",
        body,
    )


def cutout_sheet(title: str, description: str, kinds: list[str]) -> str:
    """Draw twelve broad numbered cards for cutting on their outer lines."""
    body = word(
        45, 151, "Cut on outer boxes. Print more copies for larger sets.", 15, 700
    )
    for index, kind in enumerate(kinds):
        column, row = index % 3, index // 3
        x, y = 45 + column * 240, 180 + row * 205
        body += sharp_box(x, y, 224, 181, "white").replace(
            "<rect ", f'<rect data-card-kind="{kind}" ', 1
        )
        if kind != "blank":
            body += shape_icon(kind, x + 112, y + 78)
        body += word(x + 16, y + 163, f"CARD {index + 1}", 12, 700)
    return page(title, description, body)


def blanks() -> str:
    """Make reusable broad equal-sharing cards."""
    return cutout_sheet(
        "Twelve broad blank paper cards",
        "Print more than one sheet for larger fictional collections.",
        ["blank"] * 12,
    )


def shape_cutouts() -> str:
    """Make broad geometric cards in exact practice counts."""
    kinds = [
        "circle",
        "triangle",
        "circle",
        "square",
        "triangle",
        "circle",
        "rectangle",
        "triangle",
        "square",
        "circle",
        "rectangle",
        "triangle",
    ]
    return cutout_sheet(
        "Broad shape cutouts for patterns",
        "Four circles, four triangles, two squares and two rectangles.",
        kinds,
    )


def teacher_checks() -> str:
    """Keep exact fresh-check preparation on one teacher-held page."""
    body = box(45, 150, 704, 380, BLUE)
    body += word(68, 194, "TEACHER HELD · Check A · Day 175", 20, 700)
    body += word(68, 238, "Story 1: TEN blank cards; TWO trays; share equally.", 16)
    body += word(68, 276, "Story 2: reset; TEN other cards; groups of TWO.", 16)
    body += word(68, 314, "Fix DESK A, DESK B and PUPPET markers.", 16)
    body += word(68, 352, "Place a group BETWEEN desks; another BESIDE puppet.", 15)
    body += word(68, 404, "Keep group counts off the child's first view.", 15)
    body += word(68, 454, "No real people's needs are being judged.", 15)
    body += box(45, 560, 704, 380, GREEN)
    body += word(68, 604, "TEACHER HELD · Check B · Day 180", 20, 700)
    body += word(68, 649, "Fresh unit: RECTANGLE · CIRCLE · CIRCLE.", 17)
    body += word(68, 689, "Two complete repeats; then THREE empty places.", 17)
    body += word(68, 733, "Fictional station: rectangular board, circular marker.", 15)
    body += word(68, 777, "Child creates either matching broad shape.", 16)
    body += word(68, 828, "Public key: formative only; not secure exams.", 15)
    body += word(45, 984, "Keep fresh setup away from earlier practice.", 14, 700)
    return page(
        "Fresh checks: teacher preparation",
        "Two new fictional tasks; hold the answers until first response.",
        body,
    )


def fresh_station() -> str:
    """Draw the original learner-facing fictional station for Check B."""
    body = word(
        45, 155, "New made-up paper station: look at the object boundaries.", 17, 700
    )
    body += box(45, 190, 704, 700, BLUE)
    body += sharp_box(100, 292, 370, 270, "white")
    body += word(145, 454, "ROUTE BOARD", 21, 700)
    body += (
        f'<circle cx="600" cy="430" r="100" fill="{GREEN}" '
        f'stroke="{INK}" stroke-width="5"/>'
    )
    body += word(517, 575, "PLATFORM", 17, 700)
    body += word(536, 609, "MARKER", 17, 700)
    body += box(75, 710, 644, 135, PEACH)
    body += word(100, 756, "Find two familiar shapes in this invented drawing.", 17)
    body += word(100, 803, "Trace or feel a boundary; say why each name fits.", 16)
    body += word(
        45, 946, "This page is the child picture, not the staff answer key.", 15
    )
    return page(
        "Fresh fictional station shapes",
        "Check B learner picture: one route board and one platform marker.",
        body,
    )


PAGES = {
    "share-and-group-mat": share_mat,
    "room-location-mat": room_mat,
    "repeat-unit-mat": repeat_mat,
    "shape-reason-cards": shape_reason,
    "blank-share-cards": blanks,
    "practice-cutouts": shape_cutouts,
    "teacher-held-checks": teacher_checks,
    "fresh-station-drawing": fresh_station,
}


def main() -> None:
    """Write SVG and PDF for every authored page."""
    for stem, make in PAGES.items():
        svg = HERE / f"{stem}.svg"
        pdf = HERE / f"{stem}.pdf"
        svg.write_text(make(), encoding="utf-8")
        subprocess.run(
            ["rsvg-convert", "-f", "pdf", "-o", str(pdf), str(svg)],
            check=True,
        )
        print(stem)


if __name__ == "__main__":
    main()
