"""Writes a document whose pages link out of themselves and to each other.

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

A link draws nothing, so nothing on the page proves it is there: only a reader
does, by following it. The first page carries a table of contents whose lines lead
to the pages after it, and an address that leaves the document; each of the pages
after it leads back.

The chapter titles and the lines around them are held in `Words`, once per language,
and `HQF_PDF_LANG` picks which set is drawn. A chapter title is written once and read
twice: it is what the contents shows, and what the navigation panel shows.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The address the contents leaves the document by. It is not language.
ADDRESS = "https://example.org/hqf-pdf"


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

    A chapter title is written once and read twice: the contents draws it, and the
    navigation panel carries it. Both read the same field, so the two can never fall
    out of step.
    """

    # The line at the head of the contents, and the name its bookmark takes.
    contents: str
    # The line that says which text on the page can be clicked.
    what_is_clickable: str
    # The chapters the contents lists, in the order they are laid out.
    chapters: tuple[str, str, str]
    # The line each chapter page leads back by.
    back: str
    # The title the document carries in its information dictionary.
    document_title: str


# The document in English.
ENGLISH = Words(
    contents="Contents",
    what_is_clickable="Blue text is clickable; black text is not.",
    chapters=("What a link is", "What a link draws", "Where a link goes"),
    back="Back to the contents",
    document_title="A document that links to itself",
)

# The document in French.
FRENCH = Words(
    contents="Sommaire",
    what_is_clickable="Le texte bleu est cliquable, le noir ne l'est pas.",
    chapters=("Ce qu'est un lien", "Ce qu'un lien dessine", "Où mène un lien"),
    back="Retour au sommaire",
    document_title="Un document qui renvoie à lui-même",
)


# 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 contents and the chapter titles are set at.
SIZE = 14.0


def contents_page(handle: hqf_pdf.FontHandle, words: Words) -> hqf_pdf.Page:
    """The contents: one clickable line per chapter, and an address that leaves."""
    content = hqf_pdf.Content()
    page = hqf_pdf.Page.a4()

    content.draw_text(handle, 20.0, 72.0, 760.0, words.contents)

    # A black line that is not a link, beside the blue lines that are.
    content.draw_text(handle, 10.0, 72.0, 735.0, words.what_is_clickable)

    top = 700.0
    for index, chapter in enumerate(words.chapters):
        line = f"{index + 1}. {chapter}"
        content.set_fill(hqf_pdf.Rgb(0.0, 0.2, 0.8))
        content.draw_text(handle, SIZE, 72.0, top, line)
        content.set_fill(hqf_pdf.Rgb(0.0, 0.0, 0.0))
        # Chapter one is the page after this one, which is index 1.
        page.add_link(
            hqf_pdf.Link.to_page(72.0, top - 3.0, handle.measure(line, SIZE), SIZE, index + 1)
        )
        top -= SIZE * 2.0

    content.set_fill(hqf_pdf.Rgb(0.0, 0.2, 0.8))
    content.draw_text(handle, SIZE, 72.0, top - 20.0, ADDRESS)
    content.set_fill(hqf_pdf.Rgb(0.0, 0.0, 0.0))
    page.add_link(
        hqf_pdf.Link.to_uri(72.0, top - 23.0, handle.measure(ADDRESS, SIZE), SIZE, ADDRESS)
    )

    page.set_content(content)
    return page


def chapter_page(handle: hqf_pdf.FontHandle, words: Words, index: int) -> hqf_pdf.Page:
    """A chapter page, with a line leading back to the contents."""
    content = hqf_pdf.Content()
    page = hqf_pdf.Page.a4()

    content.draw_text(handle, 20.0, 72.0, 760.0, f"{index + 1}. {words.chapters[index]}")

    content.set_fill(hqf_pdf.Rgb(0.0, 0.2, 0.8))
    content.draw_text(handle, SIZE, 72.0, 700.0, words.back)
    content.set_fill(hqf_pdf.Rgb(0.0, 0.0, 0.0))
    page.add_link(
        hqf_pdf.Link.to_page(72.0, 697.0, handle.measure(words.back, SIZE), SIZE, 0)
    )

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

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

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

    document.add_page(contents_page(handle, words))
    for index in range(len(words.chapters)):
        document.add_page(chapter_page(handle, words, index))

    # The same contents again, as the panel a reader navigates by.
    document.add_bookmark(
        hqf_pdf.Bookmark(
            words.contents,
            0,
            children=[
                hqf_pdf.Bookmark(f"{index + 1}. {chapter}", index + 1)
                for index, chapter in enumerate(words.chapters)
            ],
            is_open=True,
        )
    )

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


if __name__ == "__main__":
    main()
