"""Hangs links and marks on text the engine has already placed, from the boxes
it reports rather than measured by hand.

The Python twin of the `write_linked_text` example in Rust. A flow and a table
are drawn, and then asked where each line and each cell landed. A pale band is
painted behind a paragraph's first line, one line is underlined and made
clickable, and one table cell is boxed and made clickable — every rectangle
taken from `line_boxes` or `cell_box`, none of it measured.

The words are held in `Words`, once per language, and `HQF_PDF_LANG` picks which set is
drawn. The addresses the two links go to, the product's name and its version number
stand the same in every language.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The left edge every block shares.
LEFT = 70.0
# The width every block is set to.
WIDTH = 455.0

# Where the clickable line goes, and what it is drawn with after the words that
# introduce it.
CTA_URL = "https://example.org/hqf-pdf/terms"
# Where the boxed table cell goes.
LICENCE_URL = "https://example.org/hqf-pdf/licence"
# What the table names in its first row of values, and the version under it.
PRODUCT_NAME = "hqf-pdf"
VERSION_NUMBER = "1.0"


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

    What is not language stays out of it: the two addresses, the product's name and its
    version number read the same wherever the page is read.
    """

    # The title set at the head of the page.
    title: str
    # The paragraph whose first line is painted behind.
    intro: str
    # What stands before the address, on the line that is underlined and made clickable.
    cta_before: str
    # The two column headings of the table.
    field: str
    value: str
    # What each row of the table is called.
    product: str
    licence: str
    version: str
    # The value of the licence row, the cell the box makes clickable.
    licence_value: str

    def cta(self) -> str:
        """Return the line that is drawn, underlined and made clickable."""
        return f"{self.cta_before}{CTA_URL}"


# The page in English.
ENGLISH = Words(
    title="Boxes over what the engine placed",
    intro=(
        "The engine knows where every line and every cell lands, "
        "down to the point. This paragraph was flowed into a column, and the pale band "
        "was painted behind its first line from the box the engine reported, not "
        "measured by hand. The same boxes make a line clickable and draw a rule exactly "
        "under it."
    ),
    cta_before="Read the terms at ",
    field="Field",
    value="Value",
    product="Product",
    licence="Licence",
    version="Version",
    licence_value="See the licence online",
)

# The page in French.
FRENCH = Words(
    title="Des cadres posés sur ce que le moteur a placé",
    intro=(
        ("Le moteur sait où tombe chaque ligne et chaque cellule, au point près. Ce "
         "paragraphe a été coulé dans une colonne, et la bande pâle a été peinte "
         "derrière sa première ligne à partir du cadre que le moteur a indiqué, sans "
         "rien mesurer à la main. Les mêmes cadres rendent une ligne cliquable et "
         "tracent un filet exactement dessous.")
    ),
    cta_before="Lisez les conditions sur ",
    field="Champ",
    value="Valeur",
    product="Produit",
    licence="Licence",
    version="Version",
    licence_value="Voir la licence en ligne",
)

# The page in Dutch.
DUTCH = Words(
    title="Kaders over wat de motor plaatste",
    intro=(
        "De motor weet waar elke regel en elke cel terechtkomt, tot op de punt. Deze "
        "alinea is in een kolom gegoten, en de lichte band is achter de eerste regel "
        "geschilderd vanuit het kader dat de motor teruggaf, niet met de hand "
        "gemeten. Dezelfde kaders maken een regel klikbaar en trekken er precies een "
        "lijn onder."
    ),
    cta_before="Lees de voorwaarden op",
    field="Veld",
    value="Waarde",
    product="Product",
    licence="Licentie",
    version="Versie",
    licence_value="Bekijk de licentie online",
)

# The page in Portuguese.
PORTUGUESE = Words(
    title="Caixas sobre o que o motor colocou",
    intro=(
        "O motor sabe onde cai cada linha e cada célula, ao ponto. Este parágrafo foi "
        "vertido numa coluna, e a faixa clara foi pintada por trás da primeira linha "
        "a partir da caixa que o motor devolveu, não medida à mão. As mesmas caixas "
        "tornam uma linha clicável e traçam um filete exatamente por baixo."
    ),
    cta_before="Leia as condições em",
    field="Campo",
    value="Valor",
    product="Produto",
    licence="Licença",
    version="Versão",
    licence_value="Ver a licença online",
)

# The page in Italian.
ITALIAN = Words(
    title="Riquadri su ciò che il motore ha collocato",
    intro=(
        "Il motore sa dove cade ogni riga e ogni cella, al punto tipografico. Questo "
        "paragrafo è stato versato in una colonna, e la fascia chiara è stata dipinta "
        "dietro la sua prima riga dal riquadro fornito dal motore, non misurato a "
        "mano. Gli stessi riquadri rendono cliccabile una riga e tracciano un filetto "
        "esattamente sotto."
    ),
    cta_before="Leggete le condizioni su",
    field="Campo",
    value="Valore",
    product="Prodotto",
    licence="Licenza",
    version="Versione",
    licence_value="Vedere la licenza online",
)

# The page in Spanish.
SPANISH = Words(
    title="Cajas sobre lo que colocó el motor",
    intro=(
        "El motor sabe dónde cae cada línea y cada celda, con precisión de un punto. "
        "Este párrafo se vertió en una columna, y la franja clara se pintó detrás de "
        "su primera línea con la caja que dio el motor, no medida a mano. Las mismas "
        "cajas hacen una línea clicable y trazan una raya justo debajo."
    ),
    cta_before="Lea las condiciones en ",
    field="Campo",
    value="Valor",
    product="Producto",
    licence="Licencia",
    version="Versión",
    licence_value="Ver la licencia en línea",
)

# The page in German.
GERMAN = Words(
    title="Rahmen über dem, was die Engine platziert hat",
    intro=(
        "Die Engine weiß auf den Punkt genau, wo jede Zeile und jede Zelle landet. "
        "Dieser Absatz wurde in eine Spalte gesetzt, und das blasse Band wurde hinter "
        "seine erste Zeile gemalt, nach dem Rahmen, den die Engine meldete, nicht von "
        "Hand gemessen. Dieselben Rahmen machen eine Zeile anklickbar und ziehen eine "
        "Linie genau darunter."
    ),
    cta_before="Die Bedingungen stehen unter ",
    field="Feld",
    value="Wert",
    product="Produkt",
    licence="Lizenz",
    version="Version",
    licence_value="Die Lizenz online ansehen",
)


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


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

    document = hqf_pdf.Document()
    document.set_license(_licence.licensed())
    handle = document.add_font(hqf_pdf.Font.from_path(_out.font_path()))

    content = hqf_pdf.Content()

    # The title.
    title = hqf_pdf.TextFlow(handle, 18.0)
    title_lines = title.break_lines(words.title, WIDTH)
    title.draw(content, title_lines, LEFT, 790.0, WIDTH)

    # A paragraph, with the box of its first line painted behind it.
    intro = hqf_pdf.TextFlow(handle, 11.0, leading=15.0)
    intro_lines = intro.break_lines(words.intro, WIDTH)
    band = intro.line_boxes(intro_lines, LEFT, 750.0, WIDTH)[0]
    content.save_state()
    content.set_fill(hqf_pdf.Rgb(1.0, 0.93, 0.6))
    content.rect(band.x, band.y, band.width, band.height)
    content.fill()
    content.restore_state()
    intro.draw(content, intro_lines, LEFT, 750.0, WIDTH)

    # One line, drawn, then underlined and linked from its own box.
    cta = hqf_pdf.TextFlow(handle, 12.0, color=hqf_pdf.Rgb(0.0, 0.2, 0.8))
    cta_lines = cta.break_lines(words.cta(), WIDTH)
    cta.draw(content, cta_lines, LEFT, 655.0, WIDTH)
    link_box = cta.line_boxes(cta_lines, LEFT, 655.0, WIDTH)[0]
    content.save_state()
    content.set_fill(hqf_pdf.Rgb(0.0, 0.2, 0.8))
    content.rect(link_box.x, link_box.y, link_box.width, 0.6)
    content.fill()
    content.restore_state()

    # A table, then the box of one value cell drawn and linked.
    columns = hqf_pdf.Columns(
        [hqf_pdf.ColumnWidth.points(140.0), hqf_pdf.ColumnWidth.points(315.0)],
        WIDTH,
    )
    pad = hqf_pdf.Padding.symmetric(6.0, 4.0)
    table = hqf_pdf.Table(columns)
    table.header(1)
    table.rule(hqf_pdf.Rule.frame(), hqf_pdf.Stroke(0.8))
    table.rule(
        hqf_pdf.Rule.horizontal_other(),
        hqf_pdf.Stroke(0.25, color=hqf_pdf.Rgb(0.75, 0.75, 0.75)),
    )
    table.push(
        hqf_pdf.Row(
            cells=[
                hqf_pdf.Cell(handle, 10.0, words.field, padding=pad),
                hqf_pdf.Cell(handle, 10.0, words.value, padding=pad),
            ]
        )
    )
    table.push(
        hqf_pdf.Row(
            cells=[
                hqf_pdf.Cell(handle, 10.0, words.product, padding=pad),
                hqf_pdf.Cell(handle, 10.0, PRODUCT_NAME, padding=pad),
            ]
        )
    )
    table.push(
        hqf_pdf.Row(
            cells=[
                hqf_pdf.Cell(handle, 10.0, words.licence, padding=pad),
                hqf_pdf.Cell(handle, 10.0, words.licence_value, padding=pad),
            ]
        )
    )
    table.push(
        hqf_pdf.Row(
            cells=[
                hqf_pdf.Cell(handle, 10.0, words.version, padding=pad),
                hqf_pdf.Cell(handle, 10.0, VERSION_NUMBER, padding=pad),
            ]
        )
    )

    placed = table.fit(LEFT, 610.0, 200.0)
    placed.draw(content)
    cell = placed.cell_box(2, 1)
    content.save_state()
    content.set_stroke(hqf_pdf.Rgb(0.8, 0.0, 0.0))
    content.set_line_width(1.0)
    content.rect(cell.x, cell.y, cell.width, cell.height)
    content.stroke()
    content.restore_state()

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    page.add_link(link_box.link_to_uri(CTA_URL))
    page.add_link(cell.link_to_uri(LICENCE_URL))
    document.add_page(page)

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


if __name__ == "__main__":
    main()
