"""Writes a document whose pages are numbered by their labels, not by their position.

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

Whether the labels work is not a question the bytes can answer: it is answered by
the page box of a reader, which is the one place they show. So every page here says
what a reader ought to be showing for it — open the file and the two either agree or
they do not.

What each page says is written in the language `HQF_PDF_LANG` names. The labels
themselves are not: `i`, `1` and `A-1` are what a reader shows in its page box, they
come from the numbering style and the prefix the file writes, and a page that
translated them would no longer say what the file asks for.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# How far in from the left edge of the sheet every line is set, in points.
LEFT = 72.0

# How many sheets the document runs to, which each page says of itself.
SHEETS = 7

# The size each line of a page is set at, in points, in the order they are drawn.
SIZES = [12.0, 9.0, 9.0, 14.0, 20.0]

# Where the baseline of each line sits, in points up from the foot of the sheet, in the
# order they are drawn.
BASELINES = [772.0, 752.0, 738.0, 700.0, 640.0]


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

    What a reader shows in its page box is not among them: `i`, `1` and `A-1` come from
    the numbering style and the prefix the file writes, and the page carries them so
    that the two can be read against each other.
    """

    # What the document is called, in what the file says of itself.
    title: str
    # The three lines at the head of every page, which say what page labels are and
    # where they show.
    head: tuple[str, str, str]
    # What stands before a sheet's number.
    sheet: str
    # What stands between a sheet's number and the count of them.
    of: str
    # What stands before the label a reader ought to be showing.
    shows_as: str


# The pages in English.
ENGLISH = Words(
    title="A document numbered by its labels",
    head=(
        "Page labels number the pages for the reader.",
        "Roman numerals for the front matter, arabic for the body, "
        "a prefix for the annex.",
        "The label shows in a reader's page box, not the sheet number below.",
    ),
    sheet="Sheet",
    of="of",
    shows_as="A reader shows this page as:",
)

# The pages in French.
FRENCH = Words(
    title="Un document numéroté par ses étiquettes",
    head=(
        "Les étiquettes de page numérotent les pages pour le lecteur.",
        "Chiffres romains pour les pages liminaires, arabes pour le corps, "
        "un préfixe pour l'annexe.",
        "L'étiquette s'affiche dans la case du lecteur, pas le numéro de "
        "feuille ci-dessous.",
    ),
    sheet="Feuille",
    of="sur",
    shows_as="Un lecteur affiche cette page ainsi :",
)

# 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 runs the document is made of: the page each starts on counting from zero, the
# label it is numbered by, and what a reader ought to show for each of its pages.
RUNS = [
    (0, hqf_pdf.PageLabel(hqf_pdf.LabelStyle.LowerRoman), ["i", "ii"]),
    (2, hqf_pdf.PageLabel(hqf_pdf.LabelStyle.Decimal), ["1", "2", "3"]),
    (5, hqf_pdf.PageLabel(hqf_pdf.LabelStyle.Decimal, prefix="A-"), ["A-1", "A-2"]),
]


def lines(words: Words, sheet: int, shown: str) -> list[str]:
    """What one page says: what page labels are, which sheet it is, and its label."""
    return [
        *words.head,
        f"{words.sheet} {sheet} {words.of} {SHEETS}",
        f"{words.shows_as} {shown}",
    ]


def page(
    handle: hqf_pdf.FontHandle, words: Words, sheet: int, shown: str
) -> hqf_pdf.Page:
    """A page that says which sheet it is and what a reader ought to call it."""
    content = hqf_pdf.Content()
    for line, size, top in zip(lines(words, sheet, shown), SIZES, BASELINES):
        content.draw_text(handle, size, LEFT, top, line)

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


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("page-labels.pdf", language)).stem)

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    document.set_info("Title", words.title)

    handle = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))

    sheet = 1
    for start, label, shown_as in RUNS:
        for shown in shown_as:
            document.add_page(page(handle, words, sheet, shown))
            sheet += 1
        document.label_pages(start, label)

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


if __name__ == "__main__":
    main()
