#!/usr/bin/env python3
"""Create three original, one-page A4 SVG/PDF English source aids."""

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 = "#182730"
TEAL = "#126371"
MUTED = "#41545d"
PALE = "#eaf5f4"


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


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


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


def sheet(title: str, desc: str, body: list[str], footer: str) -> str:
    start = [
        ('<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"/>',
        rect(34, 25, 726, 106, fill=PALE),
        txt(54, 64, "SUBJECTNEST / YEAR 11 / GENERAL ENGLISH", 16, True, TEAL),
        txt(54, 107, title, 29, True),
    ]
    end = [line(34, 1072, 760, 1072), txt(40, 1100, footer, 13, color=MUTED), '</svg>']
    return "\n".join(start + body + end) + "\n"


def source_lens() -> str:
    body = [txt(40, 165, "Read the words first. Then explain the inference.", 20, True),
            txt(40, 198, "Use this numbered path with any public or literary text.", 16)]
    items = [
        ("1  MAKER + AUDIENCE", "Who made this? For whom? What kind of text?"),
        ("2  EXACT CHOICE", "Copy a short phrase, image, action or number."),
        ("3  POSSIBLE EFFECT", "How might this position one possible reader?"),
        ("4  LIMIT", "What does the text leave open or explicitly rule out?"),
        ("5  CAREFUL CLAIM", "In this text, the choice may ...; it does not prove ..."),
    ]
    for i, (head, prompt) in enumerate(items):
        y = 223 + i * 160
        body.extend([rect(45, y, 704, 142), rect(58, y + 11, 678, 43, fill=PALE),
                     txt(74, y + 41, head, 18, True, TEAL),
                     txt(74, y + 87, prompt, 17),
                     line(73, y + 114, 721, y + 114)])
    body.extend([txt(44, 1048, "Check: is an unknown being turned into an outcome?", 17, True)])
    return sheet("Source lens",
                 "Five numbered vertical cards: maker and audience, exact choice, possible effect, limit, careful claim. Each has a short written prompt and blank line. All meaning is in words, not colour.",
                 body, "Original source-thinking sheet · full text and tactile route supplied")


def voice_map() -> str:
    body = [txt(40, 166, "Compare public invitation with one fictional voice.", 19, True),
            txt(40, 196, "A character cannot stand for an entire community.", 16)]
    headers = [("PUBLIC TEXT", 43), ("LITERARY SCENE", 403)]
    for head, x in headers:
        body.extend([rect(x, 219, 348, 525), rect(x + 10, 231, 328, 48, fill=PALE),
                     txt(x + 19, 265, head, 18, True, TEAL)])
        for label, y in (("Maker / reader", 314), ("Exact phrase or action", 431),
                         ("Likely invitation or effect", 548), ("What remains unknown", 665)):
            body.extend([txt(x + 17, y, label, 16, True),
                         line(x + 18, y + 38, x + 328, y + 38),
                         line(x + 18, y + 63, x + 328, y + 63)])
    body.extend([rect(43, 775, 708, 266, fill="#f8fbfb"),
                 txt(60, 810, "COMPARE WITHOUT FLATTENING VOICES", 18, True, TEAL),
                 txt(60, 857, "Both sources select ...", 18), line(60, 881, 733, 881),
                 txt(60, 923, "Only the scene shows ...", 18), line(60, 947, 733, 947),
                 txt(60, 989, "Neither source proves ...", 18), line(60, 1013, 733, 1013)])
    return sheet("Two-voice map",
                 "Two columns compare a public text and a literary scene. Each has maker and reader, exact phrase or action, possible effect and unknown lines. A bottom box prompts both sources select, only the scene shows, neither source proves.",
                 body, "Original comparison mat · full text and tactile route supplied")


def public_editor() -> str:
    body = [txt(40, 164, "Revise a line so an absent reader can use it.", 20, True),
            txt(40, 194, "Keep the before line and give a source-based reason.", 16)]
    fields = [
        ("WHO WILL READ THIS?", 218, 92),
        ("BEFORE: exact draft line", 329, 178),
        ("AFTER: revised public line", 526, 178),
    ]
    for label, y, h in fields:
        body.extend([rect(43, y, 708, h), rect(54, y + 10, 686, 43, fill=PALE),
                     txt(69, y + 40, label, 17, True, TEAL)])
        for ly in range(y + 84, y + h - 8, 39):
            body.append(line(65, ly, 729, ly))
    body.extend([rect(43, 725, 708, 314, fill="#f8fbfb"),
                 txt(60, 761, "CHECK EACH CHANGE AGAINST THE SOURCE", 18, True, TEAL)])
    for label, y in (("1  Exact fact or image retained?", 808),
                     ("2  Outcome or selection limit stated?", 861),
                     ("3  Unknown turned into a question?", 914),
                     ("4  What will the reader understand differently?", 967)):
        body.extend([txt(60, y, label, 17), line(60, y + 19, 732, y + 19)])
    return sheet("Public editor",
                 "Large A4 editing sheet with reader line, before draft box, after public line box, and four source checks: exact fact, limit, unknown question, effect on reader. Blank lines remain writable.",
                 body, "Original revision sheet · full text and tactile route supplied")


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 A4 aid pairs")
    env = {**os.environ, "SOURCE_DATE_EPOCH": "1790640000"}
    for stem, maker in (("source-lens", source_lens), ("voice-map", voice_map),
                        ("public-editor", public_editor)):
        svg = HERE / f"{stem}.svg"
        pdf = HERE / f"{stem}.pdf"
        svg.write_text(maker(), encoding="utf-8")
        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()
