"""Writes an archival form: a PDF/A-3 file a reader fills in.

The Python twin of the `write_archival_form` example in Rust: the same
document, through the binding rather than through the library directly.

A form and an archival file pull in opposite directions. A form leaves its
fields for the reader's software to draw; an archival file forbids exactly
that, and demands every mark be baked into the page. This reconciles them: each
field carries its own appearance — a text value drawn as glyphs, a tick or dot
drawn as a vector — so the file needs no reader help and no font it does not
embed.

A form field draws no border of its own: the PDF standard leaves widgets
borderless by default, so a reader sees only what the page draws behind them.
This example gives every field a border, so the boxes a reader clicks are plain
to see, and says as much on the page. The borders are optional — the same form
is valid without them.

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

The labels, the options and the metadata are held in `Words`, once per language, and
`HQF_PDF_LANG` picks which set is drawn. A field's name is not among them: it is what
a filled form's data comes back under, so it stays the same whichever language the
page is drawn in.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# When the form 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-07-14T09:30:00+02:00"

# Who drew the form up, and the value the name field starts with. Neither is language.
AUTHOR = "Olivier Pons"
REGISTERED_NAME = "Ada Lovelace"

# The names the two radio buttons send back, in the order they are drawn.
PAYMENT_VALUES = ("card", "transfer")


@dataclass(frozen=True)
class Words:
    """Every word the form draws and carries, in one language.

    A field's name is not here: it is the name a filled form's data comes back under,
    and a reader that changed language would send back something else. The metadata is,
    because a reader reads it beside the page.
    """

    # The line at the head of the page.
    title: str
    # What the two lines under the title say the boxes are.
    boxes_are_fields: str
    # What the second of them says about their borders.
    borders_are_optional: str
    # The label beside the field a reader gives a name in.
    name: str
    # The label beside the field a reader gives an address in.
    email: str
    # The line beside the check box.
    subscribe: str
    # The label beside the drop-down.
    plan: str
    # The options the drop-down offers; the second is the one it starts on.
    plans: tuple[str, str]
    # The label beside the radio buttons.
    payment: str
    # The line beside each radio button, in the order they are drawn.
    payments: tuple[str, str]
    # The title the document carries in its metadata.
    document_title: str
    # What its metadata says the document is.
    document_subject: str


# The page in English.
ENGLISH = Words(
    title="Registration",
    boxes_are_fields="The boxes below are clickable form fields.",
    borders_are_optional=(
        "Their borders are optional: the standard draws none by default."
    ),
    name="Name",
    email="Email",
    subscribe="Subscribe to the newsletter",
    plan="Plan",
    plans=("Monthly", "Yearly"),
    payment="Payment",
    payments=("Card", "Transfer"),
    document_title="A registration form",
    document_subject="A fillable form that is also an archival file",
)

# The page in French.
FRENCH = Words(
    title="Inscription",
    boxes_are_fields="Les cases ci-dessous sont des champs à remplir.",
    borders_are_optional="Leur bordure est facultative : la norme n'en dessine aucune.",
    name="Nom",
    email="Courriel",
    subscribe="S'abonner à la lettre d'information",
    plan="Formule",
    plans=("Mensuelle", "Annuelle"),
    payment="Paiement",
    payments=("Carte", "Virement"),
    document_title="Un formulaire d'inscription",
    document_subject="Un formulaire à remplir qui est aussi un fichier d'archive",
)


# 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}

# The size the labels and the field text are set at.
SIZE = 12.0

# The colour every field's border is stroked in.
BORDER = hqf_pdf.Rgb.gray(0.6)
# The width every field's border is stroked at, in points.
BORDER_WIDTH = 0.75


def form_page(handle: hqf_pdf.FontHandle, words: Words) -> hqf_pdf.Page:
    """The form page: a label and a fillable box for each field, one of every
    kind."""
    content = hqf_pdf.Content()
    page = hqf_pdf.Page.a4()

    content.draw_text(handle, SIZE, 72.0, 760.0, words.title)
    content.draw_text(handle, SIZE, 72.0, 738.0, words.boxes_are_fields)
    content.draw_text(handle, SIZE, 72.0, 722.0, words.borders_are_optional)

    # A filled text field and an empty one: the empty field's baked appearance is empty,
    # which is what makes the file archival without hiding the field.
    content.draw_text(handle, SIZE, 72.0, 700.0, words.name)
    page.add_field(
        hqf_pdf.FormField(
            "Name",
            180.0,
            697.0,
            240.0,
            SIZE + 4.0,
            handle,
            SIZE,
            value=REGISTERED_NAME,
            border_color=BORDER,
            border_width=BORDER_WIDTH,
        )
    )

    content.draw_text(handle, SIZE, 72.0, 664.0, words.email)
    page.add_field(
        hqf_pdf.FormField(
            "Email",
            180.0,
            661.0,
            240.0,
            SIZE + 4.0,
            handle,
            SIZE,
            border_color=BORDER,
            border_width=BORDER_WIDTH,
        )
    )

    content.draw_text(handle, SIZE, 90.0, 628.0, words.subscribe)
    page.add_checkbox(
        hqf_pdf.CheckBox(
            "Subscribe",
            72.0,
            626.0,
            SIZE,
            SIZE,
            checked=True,
            border_color=BORDER,
            border_width=BORDER_WIDTH,
        )
    )

    content.draw_text(handle, SIZE, 72.0, 592.0, words.plan)
    page.add_choice(
        hqf_pdf.ChoiceField(
            "Plan",
            180.0,
            589.0,
            240.0,
            SIZE + 4.0,
            handle,
            SIZE,
            options=list(words.plans),
            selected=words.plans[1],
            combo=True,
            border_color=BORDER,
            border_width=BORDER_WIDTH,
        )
    )

    content.draw_text(handle, SIZE, 72.0, 556.0, words.payment)
    page.add_radio(
        hqf_pdf.RadioGroup(
            "Payment",
            [
                (PAYMENT_VALUES[0], 180.0, 553.0, SIZE, SIZE),
                (PAYMENT_VALUES[1], 320.0, 553.0, SIZE, SIZE),
            ],
            selected=PAYMENT_VALUES[0],
            border_color=BORDER,
            border_width=BORDER_WIDTH,
        )
    )
    content.draw_text(handle, SIZE, 198.0, 556.0, words.payments[0])
    content.draw_text(handle, SIZE, 338.0, 556.0, words.payments[1])

    page.set_content(content)
    return page


def main() -> None:
    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 two
    # languages do not overwrite each other in `tmp/`.
    out = _out.output_path(
        Path(_language.file_name("archival_form.pdf", language)).stem
    )

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    document.set_conformance(hqf_pdf.PdfA.A3B)
    document.set_metadata(
        hqf_pdf.Metadata(
            title=words.document_title,
            author=AUTHOR,
            subject=words.document_subject,
            producer="hqf-pdf",
            created=ISSUED,
        )
    )

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

    written = document.write(out)
    print(f"wrote {out} ({written} bytes)")


if __name__ == "__main__":
    main()
