"""Writes a quarter's meter readings claiming the third part of the archival
standard, at level U.

The third part is the one that lets a record carry a file of any kind inside
it, and level U adds that every mark of ink says which letter it stands for.
A person opens the record and reads the page; a billing system opens the
same file and reads the table.

Whether the result really is PDF/A-3U is not for us to say. `veraPDF` says,
and `scripts/check_archival.sh` asks it.

The words of the page and of its metadata are held in `Words`, once per language,
and `HQF_PDF_LANG` picks which set the record is written in.

Usage: `python examples/write_pdfa3u.py [out.pdf] [font.ttf]`
       `HQF_PDF_LANG=fr python examples/write_pdfa3u.py`
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# When the record was drawn up. The library never reads the clock — a document that
# stamped itself with the time would be a different file on every build — so the caller
# says when.
ISSUED = "2026-04-05T07:30:00+02:00"

# Who the file says wrote it, and what produced it, in every language alike.
AUTHOR = "HQF Development"
PRODUCER = "hqf-pdf-server"

# The file the record carries. What it is to the record is said in `Words`.
CARRIED_NAME = "readings.csv"
CARRIED_TYPE = "text/csv"
CHANGED = "2026-04-05T07:25:00+02:00"
CARRIED = "month,reading_kwh\n2026-01,4118\n2026-02,3902\n2026-03,3447\n"

# The readings themselves, beside the months they were taken in. Figures and units are
# the same in every language.
READINGS = "4 118 kWh\n3 902 kWh\n3 447 kWh"

@dataclass(frozen=True)
class Words:
    """Every word the record is written in, in one language."""

    # What the file says it is, in its metadata.
    title: str
    # What the file says it is about, in its metadata.
    subject: str
    # What the carried file says it is to the record.
    carried_what: str
    # The heading at the top of the page.
    heading: str
    # What the page says of the part it claims.
    body: str
    # What each line of the record asks, one a line.
    labels: str


# The record in English.
ENGLISH = Words(
    title="Meter readings, first quarter 2026",
    subject="A record that carries the figures behind it and reads back word for word",
    carried_what="The readings the page states, as a machine reads them",
    heading="Meter readings, first quarter 2026",
    body=(
        "This record claims the third part of the archival standard at the level "
        "between the plain one and the tagged one: it may carry a file of any kind, "
        "and every mark of ink on its pages says which letter it stands for. The "
        "figures below are also carried inside the file, as the comma-separated table "
        "a machine reads. A person opens the record and reads the page; a program "
        "opens the same record and takes the figures without reading anything at all."
    ),
    labels="January\nFebruary\nMarch",
)


# The record in French.
FRENCH = Words(
    title="Relevés de compteur, 1er trimestre 2026",
    subject=(
        "Un document qui contient les chiffres dont il découle et se relit mot pour mot"
    ),
    carried_what="Les relevés que la page indique, sous la forme que lit une machine",
    heading="Relevés de compteur, 1er trimestre 2026",
    body=(
        "Ce document déclare suivre la troisième partie de la norme d’archivage, au "
        "niveau situé entre le plus simple et le balisé : il peut contenir un fichier "
        "de toute nature, et chaque trace d’encre de ses pages dit quelle lettre elle "
        "représente. Les chiffres ci-dessous sont aussi contenus dans le fichier, sous "
        "la forme du tableau à valeurs séparées par des virgules que lit une machine. "
        "Une personne ouvre le document et lit la page ; un programme ouvre le même "
        "document et prend les chiffres sans rien lire."
    ),
    labels="Janvier\nFévrier\nMars",
)


# The record in German.
GERMAN = Words(
    title="Zählerstände, erstes Quartal 2026",
    subject=(
        ("Ein Dokument, das die Zahlen dahinter enthält und sich Wort für Wort "
         "auslesen lässt")
    ),
    carried_what="Die Zählerstände dieser Seite, so wie eine Maschine sie liest",
    heading="Zählerstände, erstes Quartal 2026",
    body=(
        ("Dieses Dokument erklärt Konformität mit dem dritten Teil der Archivnorm, auf"
         " der Stufe zwischen der einfachen und der strukturierten: Es darf eine Datei"
         " beliebiger Art enthalten, und jede Druckspur auf seinen Seiten gibt an, für"
         " welchen Buchstaben sie steht. Die Zahlen unten stecken außerdem in der "
         "Datei, als kommagetrennte Tabelle, die eine Maschine liest. Ein Mensch "
         "öffnet das Dokument und liest die Seite; ein Programm öffnet dasselbe "
         "Dokument und übernimmt die Zahlen, ohne überhaupt etwas zu lesen.")
    ),
    labels="Januar\nFebruar\nMärz",
)


# The record in Spanish.
SPANISH = Words(
    title="Lecturas del contador, 1.er trimestre 2026",
    subject=(
        ("Un documento que contiene las cifras en que se basa y cuyo texto se copia "
         "palabra por palabra")
    ),
    carried_what="Las lecturas que indica la página, tal como las lee una máquina",
    heading="Lecturas del contador, 1.er trimestre 2026",
    body=(
        ("Este documento declara cumplir la tercera parte de la norma de archivo, en "
         "el nivel intermedio entre el básico y el etiquetado: puede llevar un fichero"
         " de cualquier tipo y cada trazo de tinta de sus páginas dice qué letra "
         "representa. Las cifras de abajo también van dentro del fichero, como la "
         "tabla separada por comas que lee una máquina. Una persona abre el documento "
         "y lee la página; un programa abre el mismo documento y toma las cifras sin "
         "leer nada en absoluto.")
    ),
    labels="Enero\nFebrero\nMarzo",
)


# The record in Italian.
ITALIAN = Words(
    title="Letture del contatore, primo trimestre 2026",
    subject=(
        ("Un documento che contiene le cifre da cui nasce e ne restituisce il testo "
         "parola per parola")
    ),
    carried_what="Le letture indicate nella pagina, come le legge una macchina",
    heading="Letture del contatore, primo trimestre 2026",
    body=(
        ("Questo documento dichiara di rispettare la terza parte della norma di "
         "archiviazione, al livello fra quello di base e quello etichettato: può "
         "contenere un file di qualsiasi tipo e ogni segno d’inchiostro delle sue "
         "pagine dice quale lettera rappresenta. Le cifre qui sotto sono contenute "
         "anche nel file, come la tabella separata da virgole che una macchina legge. "
         "Una persona apre il documento e legge la pagina; un programma apre lo stesso"
         " documento e prende le cifre senza leggere nulla.")
    ),
    labels="Gennaio\nFebbraio\nMarzo",
)


# The record in Portuguese.
PORTUGUESE = Words(
    title="Leituras do contador, 1.º trimestre de 2026",
    subject=(
        ("Um documento que contém os números que lhe dão origem e cujo texto se "
         "recupera palavra a palavra")
    ),
    carried_what="As leituras que a página indica, tal como uma máquina as lê",
    heading="Leituras do contador, 1.º trimestre de 2026",
    body=(
        "Este documento declara cumprir a terceira parte da norma de arquivo, no nível "
        "entre o básico e o etiquetado: pode conter um ficheiro de qualquer tipo e "
        "cada traço de tinta das suas páginas diz que letra representa. Os números "
        "abaixo também estão dentro do ficheiro, como a tabela separada por vírgulas "
        "que uma máquina lê. Uma pessoa abre o documento e lê a página; um programa "
        "abre o mesmo documento e recolhe os números sem ler absolutamente nada."
    ),
    labels="Janeiro\nFevereiro\nMarço",
)


# The record in Dutch.
DUTCH = Words(
    title="Meterstanden, eerste kwartaal 2026",
    subject=(
        "Een document dat de cijfers erachter bevat en woord voor woord terug te lezen "
        "is"
    ),
    carried_what="De meterstanden op de pagina, zoals een machine ze leest",
    heading="Meterstanden, eerste kwartaal 2026",
    body=(
        ("Dit document verklaart te voldoen aan het derde deel van de archiefnorm, op "
         "het niveau tussen het eenvoudige en het getagde: het mag een bestand van "
         "elke soort bevatten, en elk inktspoor op zijn pagina’s zegt voor welke "
         "letter het staat. De cijfers hieronder zitten ook in het bestand, als de "
         "door komma’s gescheiden tabel die een machine leest. Een mens opent het "
         "document en leest de pagina; een programma opent hetzelfde document en neemt"
         " de cijfers over zonder iets te lezen.")
    ),
    labels="Januari\nFebruari\nMaart",
)

# Every language the example is written in. A language is added by writing its own set
# of words and naming it here.
WORDS = {
    _language.ENGLISH: ENGLISH,
    _language.FRENCH: FRENCH,
    _language.GERMAN: GERMAN,
    _language.SPANISH: SPANISH,
    _language.ITALIAN: ITALIAN,
    _language.PORTUGUESE: PORTUGUESE,
    _language.DUTCH: DUTCH,
}


# The blocks of words the page carries, in the order it draws them: the box each goes
# in, the size it is set at, and the leading and alignment where it states them. A block
# the request states in several runs is one run of words here.
BLOCKS = (
    {
        "text": lambda words: words.heading,
        "size": 20.0,
        "left": 72.0,
        "top": 782.0,
        "width": 451.0,
        "set": None,
    },
    {
        "text": lambda words: words.body,
        "size": 11.0,
        "left": 72.0,
        "top": 736.0,
        "width": 451.0,
        "set": (16.0, hqf_pdf.Align.Justify),
    },
    {
        "text": lambda words: words.labels,
        "size": 11.0,
        "left": 72.0,
        "top": 596.0,
        "width": 228.0,
        "set": (17.0, hqf_pdf.Align.Left),
    },
    {
        "text": lambda words: READINGS,
        "size": 11.0,
        "left": 300.0,
        "top": 596.0,
        "width": 223.0,
        "set": (17.0, hqf_pdf.Align.Left),
    },
)


def sheet(handle: hqf_pdf.FontHandle, words: Words) -> hqf_pdf.Page:
    """The one page, block by block."""
    content = hqf_pdf.Content()
    for block in BLOCKS:
        settings = {}
        if block["set"] is not None:
            leading, align = block["set"]
            settings = {"leading": leading, "align": align}
        flow = hqf_pdf.TextFlow(handle, block["size"], **settings)
        lines = flow.break_lines(block["text"](words), block["width"])
        # The Python side opens and closes the text object itself, where the Rust side
        # leaves that to the caller.
        flow.draw(content, lines, block["left"], block["top"], block["width"])

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    return page


def main() -> None:
    """Writes the file, and says where it went."""
    language = _language.from_environment()
    words = _language.words_of(WORDS, language)

    # A named file is written as named; the default one carries the language, so the
    # languages do not overwrite each other in `tmp/`.
    out = _out.output_path(Path(_language.file_name("pdfa3u.pdf", language)).stem)

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    document.set_conformance(hqf_pdf.PdfA.A3U)
    document.set_metadata(
        hqf_pdf.Metadata(
            title=words.title,
            author=AUTHOR,
            subject=words.subject,
            producer=PRODUCER,
            created=ISSUED,
        )
    )
    document.attach(
        hqf_pdf.Attachment(
            CARRIED_NAME,
            words.carried_what,
            CARRIED_TYPE,
            hqf_pdf.Relationship.Data,
            CHANGED,
            CARRIED.encode(),
        )
    )

    handle = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))
    document.add_page(sheet(handle, words))

    data = document.to_bytes()
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_bytes(data)
    print(f"wrote {out}: {len(data)} bytes")


if __name__ == "__main__":
    main()
