"""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 de la boîte que le moteur a "
        "rendue, sans aucune mesure à la main. Les mêmes boîtes 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",
)


# 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 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, hqf_pdf.Rgb(0.75, 0.75, 0.75)),
    )
    table.push(
        hqf_pdf.Row(
            [
                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(
            [
                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(
            [
                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(
            [
                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()
