"""Leaves a program's own notes in the file, for itself, where no reading software
shows them.

The Python twin of the `write_own_notes` example in Rust. A press room sends a proof
out and gets it back three days later with a note in the margin. To pick the job up
again it has to know which run the sheet belongs to, which plate the page was set
for, and which ink the colour bar was drawn against — and none of that is anything a
reading software should show.

So it travels under the document instead. The file carries the run, the page carries
its plate, and the drawing placed twice on it carries the ink it was set against.
Each packet is stamped with the moment its program last touched it, and each is filed
under the name of that program, so two programs leaving notes in the same file never
read each other's.

Usage: python examples/write_own_notes.py [out.pdf]
       HQF_PDF_LANG=fr python examples/write_own_notes.py
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The margin the page is laid out inside.
MARGIN = 56.0

# How far the page runs across, between the margins.
WIDTH = 483.0

# The program the notes are filed under. Two programs leaving notes in the same file
# never read each other's, because each is filed under its own name.
PROGRAM = "PressDesk"

# When the program last touched what it left, in ISO 8601.
TOUCHED = "2026-09-07T08:15:00+02:00"

# What the file, the page and the drawing each carry.
FOR_THE_FILE = '{"run":47,"press":"K4","proof":3}'
FOR_THE_PAGE = '{"plate":"C","screen":175}'
FOR_THE_DRAWING = '{"ink":"process cyan","bar":"solid"}'

# How wide and how tall one patch of the bar is.
PATCH = (28.0, 18.0)

# How far along the bar each patch starts.
PATCH_AT = (0.0, 28.0, 56.0, 84.0, 112.0, 140.0)

# How strong the ink is in each patch.
STRENGTH = (0.15, 0.3, 0.45, 0.6, 0.8, 1.0)

# Where the bar is placed on the page, and at what scale.
PLACED = ((MARGIN, 672.0, 1.0), (MARGIN, 616.0, 0.5))


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

    # The line at the head of the page.
    title: str
    # The paragraph under it.
    body: str
    # The line under the second bar.
    caption: str


# The page in English.
ENGLISH = Words(
    title="Press proof",
    body="This sheet is a proof, and everything a reading software shows of it "
    "is on it: a title, this paragraph, and a colour bar placed twice. "
    "Under it the file states the run it belongs to, the page states the "
    "plate it was set for, and the bar states the ink it was drawn "
    "against.",
    caption="None of those three is drawn, and no reading software shows them. "
    "Each is filed under the name of the program that left it, stamped "
    "with the moment that program last touched it, and travels with "
    "the file until it opens the file again.",
)

# The page in French.
FRENCH = Words(
    title="Épreuve d'imprimerie",
    body="Cette feuille est une épreuve, et tout ce qu'un logiciel de lecture "
    "en montre est dessus : un titre, ce paragraphe, et une gamme de "
    "couleurs placée deux fois. En dessous, le fichier porte le tirage "
    "auquel il appartient, la page porte la plaque pour laquelle elle a "
    "été composée, et la gamme porte l'encre contre laquelle elle a été "
    "tracée.",
    caption="Aucune des trois n'est dessinée, et aucun logiciel de lecture ne "
    "les montre. Elles sont rangées sous le nom du programme qui les a "
    "laissées, datées du moment où il y a touché pour la dernière "
    "fois, et elles voyagent avec le fichier jusqu'à ce que ce "
    "programme le rouvre.",
)


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


def colour_bar() -> hqf_pdf.Drawing:
    """The colour bar: six patches of increasing strength, side by side."""
    bar = hqf_pdf.Content()
    for at, strength in zip(PATCH_AT, STRENGTH):
        bar.set_fill(hqf_pdf.Rgb(1.0 - strength, 1.0 - strength * 0.15, 1.0))
        bar.rect(at, 0.0, PATCH[0], PATCH[1])
        bar.fill()
    across = PATCH_AT[len(PATCH_AT) - 1] + PATCH[0]
    return hqf_pdf.Drawing(bar, hqf_pdf.Rect(0.0, 0.0, across, PATCH[1]))


def paragraph(
    content: hqf_pdf.Content,
    font: hqf_pdf.FontHandle,
    size: float,
    top: float,
    color: hqf_pdf.Rgb,
    text: str,
) -> None:
    """Writes a paragraph in a column the width of the page."""
    flow = hqf_pdf.TextFlow(font, size, leading=size * 1.4, color=color)
    lines = flow.break_lines(text, WIDTH)
    flow.draw(content, lines, MARGIN, top, WIDTH)


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

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    document.set_private_data(hqf_pdf.PrivateData(PROGRAM, TOUCHED, FOR_THE_FILE))
    font = document.add_font(hqf_pdf.Font.from_path(_out.DEFAULT_FONT))

    bar = document.add_drawing(
        colour_bar().with_private_data(
            hqf_pdf.PrivateData(PROGRAM, TOUCHED, FOR_THE_DRAWING)
        )
    )

    content = hqf_pdf.Content()
    content.draw_text(font, 16.0, MARGIN, 780.0, words.title)
    paragraph(content, font, 10.0, 770.0, hqf_pdf.Rgb.gray(0.0), words.body)
    for x, y, scale in PLACED:
        content.draw_form(bar, x, y, scale)
    paragraph(content, font, 8.5, 560.0, hqf_pdf.Rgb.gray(0.35), words.caption)

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    page.set_private_data(hqf_pdf.PrivateData(PROGRAM, TOUCHED, FOR_THE_PAGE))
    document.add_page(page)

    written = document.write(out)
    print(f"wrote {out}: {written} bytes, notes on the file, the page and the drawing")


if __name__ == "__main__":
    main()
