"""Shrinks headings to a fixed column, and turns a label up the page's spine.

The Python twin of the `write_shrink_and_turn` example in Rust. Two things the
layout does so the caller does not have to measure anything. A heading of unknown
length is set with `FontHandle.fit`, which gives the largest size at which it still
fits its column: three headings of very different lengths come out at three sizes,
each filling the same width. And a label is turned a quarter turn with
`Content.rotate`, which sets a block of text on its side about a pivot the caller
names — here, up the left margin like the title on the spine of a book.

The headings and the spine label are held in `Words`, once per language, and
`HQF_PDF_LANG` picks which set is drawn. Each set keeps three headings of very
different lengths, which is what the page is about; the name of the firm on the spine
is the same in every language.

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

from __future__ import annotations

import math
from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

PAGE_WIDTH = 595.276
MARGIN = 64.0
# The column the headings are fitted into, well inside the spine label.
COLUMN_LEFT = 120.0
COLUMN_WIDTH = PAGE_WIDTH - COLUMN_LEFT - MARGIN

# The firm the statement is drawn up for, which keeps its name in every language.
FIRM = "ACME LTD"


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

    What is not language stays out of it: the firm keeps its name. Each set keeps three
    headings of very different lengths, because what the page shows is three lengths
    coming out at three sizes on one right edge.
    """

    # The headings, longest to shortest: each is set as large as it can be and still
    # fill the column, so all three end at the same right edge.
    headings: tuple[str, str, str]
    # What the spine says after the firm's name.
    spine: str

    def spine_label(self) -> str:
        """Return the label turned up the left margin, the firm's name in front."""
        return f"{FIRM} — {self.spine}"


# The page in English.
ENGLISH = Words(
    headings=(
        "Consolidated statement of professional services rendered",
        "Summary of accounts",
        "Total due",
    ),
    spine="ANNUAL STATEMENT",
)

# The page in French.
FRENCH = Words(
    headings=(
        "Relevé consolidé des prestations de services réalisées",
        "Récapitulatif des comptes",
        "Total à payer",
    ),
    spine="RELEVÉ ANNUEL",
)


# 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 heading(
    content: hqf_pdf.Content, font: hqf_pdf.FontHandle, text: str, baseline: float
) -> None:
    """Sets a heading as large as it fits the column, right edge on the column's."""
    size = font.fit(text, COLUMN_WIDTH, 30.0)
    right = COLUMN_LEFT + COLUMN_WIDTH
    content.draw_text(font, size, right - font.measure(text, size), baseline, text)


def spine_label(
    content: hqf_pdf.Content, font: hqf_pdf.FontHandle, text: str
) -> None:
    """Turns a label a quarter turn up the left margin, about its own start."""
    pivot_x = MARGIN
    pivot_y = MARGIN

    content.save_state()
    content.set_fill(hqf_pdf.Rgb.gray(0.55))
    # Turned a quarter turn about the pivot, the label is then drawn as if it ran along
    # the bottom from there: the turn carries it up the left margin.
    content.rotate(math.pi / 2, pivot_x, pivot_y)
    content.draw_text(font, 12.0, pivot_x, pivot_y, text)
    content.restore_state()


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("shrink_and_turn.pdf", language)).stem
    )
    font_path = _out.font_path()

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

    content = hqf_pdf.Content()

    # A hairline down the right edge of the column, so the shared right edge of the
    # fitted headings can be seen.
    right = COLUMN_LEFT + COLUMN_WIDTH
    content.save_state()
    content.set_stroke(hqf_pdf.Rgb.gray(0.85))
    content.set_line_width(0.5)
    content.move_to(right, 760.0)
    content.line_to(right, 560.0)
    content.stroke()
    content.restore_state()

    baseline = 740.0
    for text in words.headings:
        heading(content, font, text, baseline)
        baseline -= 56.0

    spine_label(content, font, words.spine_label())

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    document.add_page(page)

    written = document.write(out)
    print(f"wrote {out}: {written} bytes, {len(words.headings)} headings fitted")


if __name__ == "__main__":
    main()
