"""Paints axial and radial gradients, each into a clipped box.

The Python twin of the `write_gradient` example in Rust. Four panels: a
horizontal two-colour gradient, a diagonal one, a radial one whose outer colour
is extended to fill the corners, and a three-stop gradient built from a stitched
function. Each is added to the document once, then painted into a rectangle the
page clips to.

The title and the four labels are held in `Words`, once per language, and `HQF_PDF_LANG`
picks which set is drawn.

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

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

import _language
import _licence
import _out

import hqf_pdf

# The width and height of every panel, in points.
BOX = (210.0, 170.0)


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

    # The title across the top of the page.
    title: str
    # The label under each of the four panels.
    horizontal: str
    diagonal: str
    radial: str
    three_stops: str


# The page in English.
ENGLISH = Words(
    title="Axial and radial gradients",
    horizontal="Axial, two colours",
    diagonal="Axial, on the diagonal",
    radial="Radial, outer extended",
    three_stops="Axial, three stops",
)

# The page in French.
FRENCH = Words(
    title="Dégradés en ligne droite et en cercle",
    horizontal="En ligne droite, deux couleurs",
    diagonal="En ligne droite, en diagonale",
    radial="En cercle, couleur extérieure prolongée",
    three_stops="En ligne droite, trois couleurs",
)


# 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 panel(content, font, shading, x, y, label):
    """Paint a gradient into the box at (x, y), sized BOX, and label it."""
    content.save_state()
    content.rect(x, y, BOX[0], BOX[1])
    content.clip()
    content.end_path()
    content.draw_shading(shading)
    content.restore_state()

    content.draw_text(font, 10.0, x, y - 15.0, label)


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

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

    # Left column x, right column x, top row foot, bottom row foot.
    left, right, top, bottom = 70.0, 315.0, 560.0, 320.0

    # A horizontal two-colour gradient across the top-left box.
    horizontal = document.add_shading(
        hqf_pdf.Axial.rgb(
            (left, top),
            (left + BOX[0], top),
            hqf_pdf.Rgb(0.85, 0.12, 0.12),
            hqf_pdf.Rgb(0.12, 0.2, 0.8),
        )
    )

    # A diagonal two-colour gradient across the top-right box.
    diagonal = document.add_shading(
        hqf_pdf.Axial.rgb(
            (right, bottom + BOX[1]),
            (right + BOX[0], top + BOX[1]),
            hqf_pdf.Rgb(0.95, 0.8, 0.1),
            hqf_pdf.Rgb(0.1, 0.55, 0.2),
        )
    )

    # A radial gradient in the bottom-left box, its outer colour extended so it reaches
    # the corners.
    radial = document.add_shading(
        hqf_pdf.Radial.rgb(
            (left + BOX[0] / 2.0, bottom + BOX[1] / 2.0, 0.0),
            (left + BOX[0] / 2.0, bottom + BOX[1] / 2.0, BOX[0] / 2.0),
            hqf_pdf.Rgb(1.0, 1.0, 1.0),
            hqf_pdf.Rgb(0.1, 0.15, 0.45),
        ).extend(False, True)
    )

    # A three-stop gradient in the bottom-right box, from a stitched function: red to
    # green over the first half, green to blue over the second.
    rainbow_function = hqf_pdf.Function.stitching(
        (0.0, 1.0),
        [
            hqf_pdf.Function.exponential(
                (0.0, 1.0), 1.0, ([0.85, 0.12, 0.12], [0.12, 0.6, 0.2])
            ),
            hqf_pdf.Function.exponential(
                (0.0, 1.0), 1.0, ([0.12, 0.6, 0.2], [0.12, 0.2, 0.8])
            ),
        ],
        [0.5],
        [(0.0, 1.0), (0.0, 1.0)],
    )
    rainbow = document.add_shading(
        hqf_pdf.Axial(
            (right, bottom),
            (right + BOX[0], bottom),
            hqf_pdf.DeviceSpace.Rgb,
            rainbow_function,
        )
    )

    content = hqf_pdf.Content()

    content.draw_text(handle, 18.0, left, 770.0, words.title)

    panel(content, handle, horizontal, left, top, words.horizontal)
    panel(content, handle, diagonal, right, top, words.diagonal)
    panel(content, handle, radial, left, bottom, words.radial)
    panel(content, handle, rainbow, right, bottom, words.three_stops)

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

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


if __name__ == "__main__":
    main()
