# SPDX-License-Identifier: Apache-2.0
"""Generate eight original illustrated A4 HASS W19–20 pages and exact alternatives."""

from __future__ import annotations

import argparse
import os
import subprocess
from html import escape
from pathlib import Path

HERE = Path(__file__).resolve().parent
INK = "#173d4f"
BLUE = "#dcebf6"
ORANGE = "#f7b462"
GREEN = "#cce8d8"
LILAC = "#eee3f8"
SAND = "#fff2dd"


def rect(x, y, w, h, fill="white", r=14, stroke=INK, sw=3):
    return f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{r}" fill="{fill}" stroke="{stroke}" stroke-width="{sw}"/>'


def txt(x, y, s, size=18, bold=False):
    return f'<text x="{x}" y="{y}" font-family="DejaVu Sans" font-size="{size}" font-weight="{700 if bold else 400}" fill="{INK}">{escape(s)}</text>'


def line(d, sw=4, colour=INK):
    return f'<path d="{d}" fill="none" stroke="{colour}" stroke-width="{sw}" stroke-linejoin="round" stroke-linecap="round"/>'


def circ(cx, cy, r, fill="white"):
    return f'<circle cx="{cx}" cy="{cy}" r="{r}" fill="{fill}" stroke="{INK}" stroke-width="3"/>'


def diamond(cx, cy, r, fill=GREEN):
    return f'<polygon points="{cx},{cy - r} {cx + r},{cy} {cx},{cy + r} {cx - r},{cy}" fill="{fill}" stroke="{INK}" stroke-width="3"/>'


def story_sign(x=280, y=285, scale=1):
    w, h = 245 * scale, 330 * scale
    b = rect(x, y, w, h, "white", 5, INK, 5)
    b += circ(x + w / 2, y + 35 * scale, 10 * scale, SAND)
    b += line(f"M{x + w / 2} {y + 25 * scale} L{x + w / 2} {y - 29 * scale}", 4)
    b += circ(x + w / 2, y + 130 * scale, 53 * scale, BLUE)
    for i in range(3):
        yy = y + (222 + i * 32) * scale
        b += line(
            f"M{x + 48 * scale} {yy} Q{x + 86 * scale} {yy - 25 * scale} {x + 124 * scale} {yy} Q{x + 162 * scale} {yy + 25 * scale} {x + 199 * scale} {yy}",
            6,
            "#315d93",
        )
    return b


def pocket(x=289, y=353):
    b = rect(x, y, 215, 280, "white", 5, INK, 5)
    b += rect(x + 56, y + 60, 104, 104, ORANGE, 2)
    b += circ(x + 71, y + 210, 17, INK) + circ(x + 145, y + 210, 17, INK)
    return b


def shelf_tag(x=286, y=322):
    b = rect(x, y, 220, 302, "white", 5, INK, 5)
    b += diamond(x + 110, y + 116, 54)
    for i in range(3):
        yy = y + 206 + i * 28
        b += line(f"M{x + 50} {yy} L{x + 170} {yy}", 9)
    return b


def notes(lines, x=68, y=285, dy=44, size=19):
    return "".join(txt(x, y + i * dy, s, size) for i, s in enumerate(lines))


def wrap_page(title, desc, body):
    return "\n".join(
        [
            '<svg xmlns="http://www.w3.org/2000/svg" width="210mm" height="297mm" viewBox="0 0 794 1123" role="img" aria-labelledby="title desc">',
            f'<title id="title">{escape(title)}</title>',
            f'<desc id="desc">{escape(desc)}</desc>',
            '<rect width="794" height="1123" fill="white"/>',
            rect(29, 30, 736, 1063),
            txt(46, 74, "SUBJECTNEST · FOUNDATION HASS · W19–20", 17, True),
            txt(46, 116, title, 25, True),
            txt(46, 148, desc, 14),
            body,
            line("M46 1041 L748 1041", 2),
            txt(
                46,
                1070,
                "Original fictional source · CC BY 4.0 · exact alternatives in pack",
                11,
            ),
            "</svg>",
            "",
        ]
    )


def sketch():
    b = txt(48, 194, "SOURCE A · UNDated OBJECT DRAWING".upper(), 18, True)
    b += rect(57, 217, 680, 533, BLUE) + story_sign()
    b += txt(91, 692, "PAPER STORY TABLE SIGN", 19, True)
    b += notes(
        [
            "A has one blue circle above three wavy lines.",
            "A has a hole at the top for hanging.",
            "The drawing does not name a maker.",
            "It does not tell whether anybody used the sign.",
        ],
        48,
        811,
        43,
        17,
    )
    return wrap_page(
        "Story Table sign · object sketch",
        "A is a drawing, not a photograph or a visit.",
        b,
    )


def maker():
    b = txt(48, 197, "SOURCE B · IVO'S MAKER NOTE · 12 JUNE", 19, True)
    b += rect(59, 234, 678, 710, SAND)
    b += rect(271, 274, 252, 231, "white", 5) + circ(398, 365, 48, BLUE)
    b += line(
        "M308 435 Q340 410 372 435 Q404 460 436 435 Q468 410 501 435", 5, "#315d93"
    )
    b += line(
        "M308 464 Q340 439 372 464 Q404 489 436 464 Q468 439 501 464", 5, "#315d93"
    )
    b += notes(
        [
            "“I made the paper sign for our pretend Story Table.",
            "I drew a blue circle and three wavy lines so my",
            "friend could find the table. I do not know whether",
            "every visitor used it.”",
        ],
        79,
        579,
        48,
        18,
    )
    b += txt(79, 832, "Writer: IVO · This is Ivo's own report and purpose.", 16, True)
    return wrap_page(
        "Ivo · maker note", "A first-person report, not a result for all visitors.", b
    )


def caption():
    b = txt(48, 195, "SOURCE C · SOL'S LATER DISPLAY CAPTION", 18, True)
    b += rect(59, 226, 678, 693, LILAC)
    b += rect(130, 282, 530, 221, "white", 5)
    b += circ(174, 326, 19, BLUE) + line("M162 371 Q177 351 191 371", 4)
    b += txt(218, 342, "COPIED FROM IVO", 18, True)
    b += notes(
        ["“I copied Ivo's note for this label.", "Ivo made the blue paper sign."],
        92,
        557,
        47,
        19,
    )
    b += line("M397 644 L397 703 M381 683 L397 703 L413 683", 5)
    b += rect(89, 727, 616, 109, SAND)
    b += txt(112, 773, "ADDED CLAIM · no visitor count given", 17, True)
    b += txt(112, 812, "Everyone found the table because of it.”", 18)
    b += txt(83, 879, "Writer: SOL · Written 14 June in this invented story.", 15)
    return wrap_page(
        "Sol · later caption", "The copied part and new claim must be kept apart.", b
    )


def visitor():
    b = txt(48, 195, "SOURCE D · TALA'S VISITOR NOTE · 15 JUNE", 18, True)
    b += rect(59, 228, 678, 699, GREEN)
    b += story_sign(85, 323, 0.53)
    b += circ(499, 404, 45, SAND) + line(
        "M499 449 L499 568 M499 494 L444 531 M499 494 L548 526 M499 568 L463 638 M499 568 L541 638",
        7,
    )
    b += line("M265 520 Q345 484 405 513", 3, "#315d93")
    b += rect(86, 673, 621, 180, "white")
    b += notes(
        [
            "“I saw the blue circle when I visited.",
            "I found the Story Table after asking Ivo",
            "where it was. I cannot speak for other visitors.”",
        ],
        105,
        719,
        42,
        17,
    )
    b += txt(88, 890, "One person's account is not everybody's account.", 16, True)
    return wrap_page(
        "Tala · one visitor account",
        "A visitor report can answer one person's route.",
        b,
    )


def sort_mat():
    b = txt(48, 195, "SORT BY WHAT THE SOURCE CAN ANSWER", 18, True)
    entries = [
        ("A · OBJECT DRAWING", "What marks can I see? Maker not named.", BLUE),
        ("B · MAKER'S NOTE", "What does Ivo report doing and wanting?", SAND),
        ("C · LATER CAPTION", "What was copied? What was added?", LILAC),
        ("D · VISITOR'S NOTE", "What did Tala alone report?", GREEN),
    ]
    for i, (head, detail, fill) in enumerate(entries):
        y = 223 + i * 183
        b += rect(59, y, 678, 155, fill)
        b += circ(109, y + 74, 31, "white") + txt(100, y + 83, head[0], 25, True)
        b += txt(163, y + 59, head, 18, True) + txt(163, y + 105, detail, 16)
    b += txt(63, 1006, "A later date does not make an unsupported claim true.", 15)
    return wrap_page(
        "Source sort mat", "Four source types; no claims about real people.", b
    )


def explain_mat():
    b = txt(48, 195, "TEACH A WILLING LISTENER WITH A SOURCE TRAIL", 17, True)
    entries = [
        ("1 · SOURCE SAYS", "Show a detail and name its source.", BLUE),
        ("2 · PERSON SAYS", "Keep one person's purpose or view attributed.", GREEN),
        ("3 · I CAN CONCLUDE", "Use only the evidence already in hand.", SAND),
        ("4 · STILL OPEN", "Ask what new approved source is needed.", LILAC),
    ]
    for i, (head, detail, fill) in enumerate(entries):
        y = 230 + i * 180
        b += rect(64, y, 662, 149, fill)
        b += txt(86, y + 48, head, 19, True) + txt(86, y + 91, detail, 16)
        b += line(f"M86 {y + 125} L702 {y + 125}", 2)
        if i < 3:
            b += line(
                f"M397 {y + 150} L397 {y + 178} M387 {y + 167} L397 {y + 178} L407 {y + 167}",
                3,
            )
    b += txt(64, 1003, "A private explanation or pointing route is fine.", 15)
    return wrap_page(
        "Explain to someone mat", "Four boxes keep claims and unknowns separate.", b
    )


def check_a():
    b = txt(48, 194, "FRESH CHECK A · POCKET CARD", 19, True)
    b += rect(59, 219, 678, 325, BLUE) + pocket(390, 249)
    b += txt(83, 256, "SOURCE 1 · unsigned drawing", 17, True)
    b += rect(59, 559, 678, 192, SAND)
    b += notes(
        [
            "SOURCE 2 · KIRA · 3 MAY",
            "“I drew the orange square and two dots on the",
            "card so my partner could pick the music game",
            "card. I do not know whether anyone else picked it.”",
        ],
        79,
        595,
        39,
        16,
    )
    b += rect(59, 772, 678, 222, LILAC)
    b += notes(
        [
            "SOURCE 3 · NOX · 5 MAY",
            "“I copied Kira's line about the square and dots.",
            "Every player picked the music game because of it.”",
        ],
        79,
        811,
        43,
        16,
    )
    return wrap_page(
        "Check A · Pocket Card", "A new invented object and two distinct writers.", b
    )


def check_b():
    b = txt(48, 194, "FRESH CHECK B · SHELF TAG", 19, True)
    b += rect(59, 220, 678, 331, GREEN) + shelf_tag(360, 239)
    b += txt(78, 256, "SOURCE 1 · unsigned drawing", 16, True)
    b += rect(59, 566, 678, 143, SAND)
    b += notes(
        [
            "SOURCE 2 · UNA · 7 MAY",
            "“I made a tag for the pretend Story Shelf.",
            "I drew a green diamond and three bars.",
            "I hoped a friend could find the shelf.”",
        ],
        79,
        591,
        29,
        15,
    )
    b += rect(59, 726, 678, 94, LILAC)
    b += notes(
        ["SOURCE 3 · REMY · 8 MAY", "“Everyone used Una's tag to find the shelf.”"],
        79,
        760,
        38,
        16,
    )
    b += rect(59, 837, 678, 166, BLUE)
    b += notes(
        [
            "SOURCE 4 · ELLIS · 9 MAY",
            "“I saw the green diamond. I asked Una where",
            "the books were. Then I found the shelf.",
            "I do not know about anyone else.”",
        ],
        79,
        868,
        31,
        15,
    )
    return wrap_page(
        "Check B · Shelf Tag", "A new invented object and one visitor's account.", b
    )


PAGES = {
    "story-sign-sketch": sketch,
    "ivo-maker-note": maker,
    "sol-display-caption": caption,
    "tala-visitor-note": visitor,
    "source-sort-mat": sort_mat,
    "explain-to-someone-mat": explain_mat,
    "check-a-pocket-card": check_a,
    "check-b-shelf-tag": check_b,
}

ALTS = {
    "story-sign-sketch": "Source A is an undated drawing. A rectangular hanging paper Story Table sign has a hole at top, one blue circle above three wavy lines (the lines are blue). The drawing does not name a maker and does not say whether anyone used the sign. Tactile/no-print: use a rectangle of paper, one hole marker, one round counter and three bent strings in that top-to-bottom order; label A aloud.",
    "ivo-maker-note": "Source B, Ivo's maker note, written 12 June in the invented story. Exact words: ‘I made the paper sign for our pretend Story Table. I drew a blue circle and three wavy lines so my friend could find the table. I do not know whether every visitor used it.’ Tactile/no-print: give a B writer token marked Ivo and a small circle plus three strings; speak the exact quotation. This is purpose, not visitor result.",
    "sol-display-caption": "Source C, Sol's later display caption, written 14 June in the invented story. Exact words: ‘I copied Ivo's note for this label. Ivo made the blue paper sign. Everyone found the table because of it.’ The page diagrams COPY then ADDED CLAIM. Tactile/no-print: lay B and C writer tiles side by side; place the maker clause between them and keep the everyone claim on a separate unverified tile.",
    "tala-visitor-note": "Source D, Tala's visitor note, written 15 June in the invented story. Exact words: ‘I saw the blue circle when I visited. I found the Story Table after asking Ivo where it was. I cannot speak for other visitors.’ The picture shows a person beside a small sign, not an actual visit. Tactile/no-print: use a Tala token and three moves SEE CIRCLE, ASK IVO, FIND TABLE; leave OTHER VISITORS blank.",
    "source-sort-mat": "Four source boxes: A OBJECT DRAWING asks what marks are visible, maker unnamed; B MAKER'S NOTE asks what Ivo reports doing and wanting; C LATER CAPTION asks what was copied and added; D VISITOR'S NOTE asks what Tala alone reports. A later date does not make an unsupported claim true. Tactile/no-print: use four large letter cards A to D, one raised border per card, and read each description exactly.",
    "explain-to-someone-mat": "Four boxes with arrows from 1 to 4: 1 SOURCE SAYS: show a detail and name its source; 2 PERSON SAYS: keep one person's purpose or view attributed; 3 I CAN CONCLUDE: use only the evidence already in hand; 4 STILL OPEN: ask what new approved source is needed. A private explanation or pointing route is fine. Tactile/no-print: four numbered raised cards in order, with a physical gap after card 3 for unknowns.",
    "check-a-pocket-card": "Fresh Check A, invented Pocket Card. Source 1 is an unsigned drawing: rectangular pocket card, orange square near top, two black dots below. Source 2, Kira's note dated 3 May: ‘I drew the orange square and two dots so my partner could pick the music game card. I do not know whether anyone else picked it.’ Source 3, Nox's caption dated 5 May: ‘I copied Kira's line about the square and dots. Every player picked the music game because of it.’ Tactile/no-print: use a rectangle, one square and two counters, then read Source 2 and Source 3 exactly from STUDENT-CHECKS.md; no answer hints.",
    "check-b-shelf-tag": "Fresh Check B, invented Shelf Tag. Source 1 is an unsigned drawing: paper tag, green diamond above three black bars. Source 2, Una's note dated 7 May: ‘I made a tag for the pretend Story Shelf. I drew a green diamond and three bars. I hoped a friend could find the shelf.’ Source 3, Remy's caption dated 8 May: ‘Everyone used Una's tag to find the shelf.’ Source 4, Ellis's note dated 9 May: ‘I saw the green diamond. I asked Una where the books were. Then I found the shelf. I do not know about anyone else.’ Tactile/no-print: use a rectangle, diamond and three bars, and four raised source numbers; read exact check text without answer hints.",
}


def write():
    for stem, fn in PAGES.items():
        svg = HERE / f"{stem}.svg"
        pdf = HERE / f"{stem}.pdf"
        svg.write_text(fn(), encoding="utf-8")
        env = dict(os.environ, SOURCE_DATE_EPOCH="1780000000")
        with pdf.open("wb") as output:
            subprocess.run(
                ["rsvg-convert", "--format", "pdf", str(svg)],
                check=True,
                stdout=output,
                env=env,
            )
    lines = [
        "# Exact linear readings and tactile/no-print routes",
        "",
        "Read the complete source words in [MATERIALS.md](../MATERIALS.md) and the complete fresh checks in [STUDENT-CHECKS.md](../STUDENT-CHECKS.md). The page text is selectable in PDF; colour is never the sole clue. The alternatives below identify every illustrated mark and every source claim needed for the same task. A child may point, sign, use AAC, move counters, dictate or use enlarged print. A tactile setup is a constructed equivalent, not a tested accessibility accommodation. Do not add a maker or outcome the source does not say.",
        "",
    ]
    for stem, reading in ALTS.items():
        lines.extend([f"## {stem}.svg / {stem}.pdf", "", reading, ""])
    lines.extend(
        [
            "The **exact full check wording and prompts** are in STUDENT-CHECKS.md; read them neutrally. The printed source quotations match those full source statements. No child-facing worked key is included.",
            "",
        ]
    )
    (HERE / "TEXT-ALTERNATIVES.md").write_text("\n".join(lines), encoding="utf-8")


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--regenerate", action="store_true")
    parser.parse_args()
    write()
    print("Generated eight A4 SVG/PDF pairs and exact alternatives")


if __name__ == "__main__":
    main()
