#!/usr/bin/env python3
"""Rebuild five original Legal Studies A4 SVG and PDF classroom 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, BLUE, MUTED, PALE = '#19323f', '#225873', '#425866', '#eaf4f8'


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


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


def page(title: str, desc: str, parts: list[str]) -> str:
    return '\n'.join([
        '<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, 28, 726, 108, PALE),
        txt(50, 63, 'SUBJECTNEST / YEAR 11 / LEGAL STUDIES', 16, bold=True),
        txt(50, 106, title, 27, bold=True),
        *parts,
        '<line x1="36" y1="1066" x2="758" y2="1066" stroke="#225873" stroke-width="2"/>',
        txt(38, 1095, 'Original model · full text and tactile route supplied', 13),
        '</svg>', '',
    ])


def rows(title: str, desc: str, intro: str,
         data: list[tuple[str, str, str]], note: str) -> str:
    parts = [txt(44, 174, intro, 17, bold=True)]
    n = len(data)
    gap = 740 // n
    for i, (head, first, second) in enumerate(data):
        y = 205 + gap * i
        parts += [box(44, y, 706, gap - 19, PALE if i % 2 == 0 else 'white'),
                  txt(61, y + 35, f'{i + 1}  {head}', 18, bold=True),
                  txt(61, y + 75, first, 15),
                  txt(61, y + 107, second, 15)]
    parts += [txt(44, 1002, note, 15, bold=True)]
    return page(title, desc, parts)


def rule_or_law() -> str:
    return rows('Rule or law?',
                'Four questions classify a venue or club rule against actual law: who made it, where is the enacted source, when is it operative, and what facts are established. The model criminal claim remains unproved.',
                'Card A: a volunteer calls a club rule a crime. Test it.', [
                    ('MAKER', 'A club or venue may make conduct rules.', 'That does not alone create a criminal offence.'),
                    ('SOURCE', 'Find a valid current legal instrument.', 'A worker statement or bill headline is not it.'),
                    ('STATUS', 'Check passage, assent and commencement.', 'A proposal and a future provision may lack force now.'),
                    ('FACTS', 'Ask what evidence establishes conduct.', 'A legal rule alone cannot prove a person acted.')],
                'Keep rule, law and proven conduct in separate boxes.')


def source_ladder() -> str:
    return rows('Source ladder',
                'Four rungs sort rumour, proposed bill, current authorised Act, and relevant judgment. A legal source still cannot prove the fictional actor damaged a panel.',
                'To test an actual legal claim, inspect authority and fit.', [
                    ('RUMOUR', 'A post can point to a question.', 'It cannot establish a current legal rule.'),
                    ('BILL', 'A proposal may show intended change.', 'It is not an operative Act.'),
                    ('ACT', 'Use the authorised current version.', 'Check provision, jurisdiction and start date.'),
                    ('JUDGMENT', 'A relevant case may interpret the law.', 'Still compare facts and court hierarchy.')],
                'An Act or case does not witness the disputed event.')


def three_arms() -> str:
    return rows('Three arms, two axes',
                'Three arms of Commonwealth government are Parliament, executive, judiciary; a separate constitutional question divides law-making powers between Commonwealth and state.',
                'Do not confuse functions with federal-state allocation.', [
                    ('PARLIAMENT', 'Legislative: debate and pass bills.', 'Ministers may also sit in Parliament.'),
                    ('EXECUTIVE', 'Administer law and public functions.', 'It cannot invent a crime by announcement.'),
                    ('COURTS', 'Interpret and apply law in cases.', 'A court does not pass a bill.'),
                    ('OTHER AXIS', 'Commonwealth / state law-making power.', 'Exclusive, concurrent, residual need a source.')],
                'Both axes can matter to one issue; check each.')


def court_path() -> str:
    return rows('Court path and proof',
                'A simplified Queensland criminal route distinguishes first-level Magistrates Court, possible serious-matter referral, appellate role, and what a legal precedent cannot prove.',
                'A report of damage is not yet a proven charge.', [
                    ('SOURCE', 'Identify the current offence and facts.', 'Do not assume a classroom story is chargeable.'),
                    ('FIRST LEVEL', 'Magistrates Court is the usual first step.', 'Particular jurisdiction needs checking.'),
                    ('SERIOUS MATTERS', 'May go to District or Supreme Court.', 'Supreme Court includes Court of Appeal.'),
                    ('PRECEDENT', 'Higher-court legal reasons may bind below.', 'They do not prove who caused this damage.')],
                'Court, legal rule and disputed conduct differ.')


def fairness() -> str:
    return rows('Fairness lens',
                'Five full-word prompts separate legal status, evidence, affected viewpoints, consequences and a bounded next step. The lesson does not decide a real case.',
                'Before a consequence, slow the claim down.', [
                    ('STATUS', 'Is this a rule, bill or operative law?', 'Check an authorised source.'),
                    ('EVIDENCE', 'What does each item actually show?', 'An allegation is not proof.'),
                    ('VIEWPOINTS', 'Who is affected and what do they seek?', 'Do not assume identity or experience.'),
                    ('CONSEQUENCE', 'What may follow from each approach?', 'Keep the implication conditional.'),
                    ('NEXT STEP', 'Recommend a fair source/check.', 'Say what remains unknown.')],
                'Reason from a source; never invent guilt.')


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument('--write', action='store_true')
    if not parser.parse_args().write:
        parser.error('pass --write to rebuild five original A4 pairs')
    env = {**os.environ, 'SOURCE_DATE_EPOCH': '1790640000'}
    for stem, maker in (('rule-or-law', rule_or_law), ('source-ladder', source_ladder),
                        ('three-arms', three_arms), ('court-path', court_path),
                        ('fairness-lens', fairness)):
        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)],
                       env=env, check=True)
        print(f'{stem}: SVG + PDF')


if __name__ == '__main__':
    main()
