"""Lays an invoice on a letterhead somebody else made.

The Python twin of the `write_overlay` example in Rust. The letterhead is a PDF:
it is read, brought in as a form, drawn under the invoice, and nothing about it
is rewritten.

The invoice's labels, and the one label the stand-in letterhead carries, are held in
`Words`, once per language, and `HQF_PDF_LANG` picks which set is drawn. The leader
dots are counted rather than typed, so a longer label in another language still ends
its amount on the same character.

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

from __future__ import annotations

import sys
from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# How many characters a billed line runs to: its label, a space, the leader dots, a
# space, then its amount. The dots take whatever is left, so the amounts end on the same
# character however long the label before them is.
LINE_CHARS = 56

# The invoice's number, and what each billed line comes to. Neither is language.
NUMBER = "1964413"
AMOUNTS = ("4 250.00 EUR", "850.00 EUR", "5 100.00 EUR")

# The letterhead's own name, address and registration number. None of them is language:
# they belong to whoever the letterhead is for.
COMPANY = "ACME Ltd"
COMPANY_ADDRESS = "12 Fleet Street — London EC4Y 1AA"
COMPANY_NUMBER = "123 456 789"

# The size each of the five invoice lines is set at, in the order they are laid down.
SIZES = (16.0, 11.0, 11.0, 11.0, 12.0)


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

    What is not language stays out of it: the invoice's number, the three amounts, and
    the letterhead's name, address and number.
    """

    # What stands on the letterhead before its registration number.
    company_number_label: str
    # What stands before the invoice's number.
    number_label: str
    # The line that gives the day the invoice was issued.
    issued: str
    # What each billed line is for, in the order they are set.
    items: tuple[str, str, str]

    def lines(self) -> list[str]:
        """The five lines the invoice sets, in order.

        Each billed line is padded out with leader dots until it runs to `LINE_CHARS`.
        """
        lines = [f"{self.number_label} {NUMBER}", self.issued]
        for item, amount in zip(self.items, AMOUNTS):
            dots = max(0, LINE_CHARS - len(item) - len(amount) - 2)
            lines.append(f"{item} {'.' * dots} {amount}")
        return lines

    def letterhead_line(self) -> str:
        """The second line of the stand-in letterhead: an address, then the number the
        company registers under, under whatever this language calls it."""
        return f"{COMPANY_ADDRESS} — {self.company_number_label} {COMPANY_NUMBER}"


# The invoice in English.
ENGLISH = Words(
    company_number_label="Company No.",
    number_label="Invoice No.",
    issued="Issued 14 July 2026",
    items=("Rendering engine development", "VAT at 20 %", "Total due"),
)

# The invoice in French.
FRENCH = Words(
    company_number_label="N° d'entreprise",
    number_label="Facture n°",
    issued="Émise le 14 juillet 2026",
    items=("Développement du moteur de rendu", "TVA à 20 %", "Total à payer"),
)


# 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 a_letterhead(words: Words) -> bytes:
    """A letterhead, for when the caller has none to hand."""
    doc = hqf_pdf.Document()
    doc.set_license(_licence.licensed())
    font = doc.add_font(hqf_pdf.Font.from_path(_out.DEFAULT_FONT))

    content = hqf_pdf.Content()
    content.save_state()
    content.set_fill(hqf_pdf.Rgb(0.91, 0.94, 0.98))
    content.rect(0.0, 742.0, 595.276, 100.0)
    content.fill()
    content.set_fill(hqf_pdf.Rgb(0.2, 0.35, 0.6))
    content.rect(0.0, 738.0, 595.276, 4.0)
    content.fill()
    content.restore_state()

    content.draw_text(font, 22.0, 56.0, 786.0, COMPANY)
    content.draw_text(font, 9.0, 56.0, 764.0, words.letterhead_line())

    page = hqf_pdf.Page.a4()
    page.set_content(content)
    doc.add_page(page)
    return doc.to_bytes()


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

    # The letterhead: the caller's, or one made here to stand in for it.
    if len(sys.argv) > 2:
        letterhead = open(sys.argv[2], "rb").read()
    else:
        letterhead = a_letterhead(words)

    reader = hqf_pdf.Reader(letterhead)
    print(f"the letterhead has {reader.page_count} page(s)")

    doc = hqf_pdf.Document()
    doc.set_license(_licence.licensed())

    template = doc.import_page(reader, 0)
    print(f"imported it: {template.width:.0f} × {template.height:.0f} points")

    font = doc.add_font(hqf_pdf.Font.from_path(_out.DEFAULT_FONT))

    content = hqf_pdf.Content()
    content.draw_form(template)

    top = 680.0
    for line, size in zip(words.lines(), SIZES):
        content.draw_text(font, size, 56.0, top, line)
        top -= size * 2.0

    page = hqf_pdf.Page(template.width, template.height)
    page.set_content(content)
    template.add_to(page)
    doc.add_page(page)

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


if __name__ == "__main__":
    main()
