#!/usr/bin/env python3
"""Render deterministic Pivot Sans tabular-money and ss02 QA proofs."""

from __future__ import annotations

import hashlib
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont

ROOT = Path(__file__).resolve().parent.parent
DIST = ROOT / "dist"
OUTPUT = DIST / "qa-visual.png"

WIDTH, HEIGHT = 1800, 1480
MONEY_BOTTOM = 1070
BACKGROUND = "#F5F6F8"
PANEL = "#FFFFFF"
INK = "#16181D"
MUTED = "#747A86"
RULE = "#D8DCE3"
ACCENT = "#167D66"
WEIGHTS = [300, 400, 500, 600, 700]
NARROW = "$1,111,111.11"
WIDE = "€9,999,999.99"
SS02_IDENTIFIER = "acct_Il1l-class"
SS02_FORMS = "l ĺ ļ ľ ŀ ł ḷ ḻ"


def sha256(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as stream:
        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


def update_release_manifest() -> None:
    manifest = DIST / "SHA256SUMS"
    if not manifest.is_file():
        raise FileNotFoundError(
            "dist/SHA256SUMS is missing; run pipeline/build.py first"
        )
    entries = {}
    for line in manifest.read_text().splitlines():
        if line.strip():
            checksum, relative = line.split(maxsplit=1)
            entries[relative.removeprefix("*")] = checksum
    entries[OUTPUT.relative_to(DIST).as_posix()] = sha256(OUTPUT)
    manifest.write_text(
        "".join(
            f"{checksum}  {relative}\n"
            for relative, checksum in sorted(entries.items())
        )
    )


def variable_font(path: Path, size: int, weight: int):
    font = ImageFont.truetype(
        str(path),
        size=size,
        layout_engine=ImageFont.Layout.RAQM,
    )
    font.set_variation_by_axes([float(weight)])
    return font


def draw_panel(
    draw: ImageDraw.ImageDraw,
    x: int,
    title: str,
    font_path: Path,
    label_font,
    small_font,
):
    panel_width = 840
    panel_top = 118
    draw.rounded_rectangle(
        (x, panel_top, x + panel_width, MONEY_BOTTOM),
        radius=20,
        fill=PANEL,
        outline=RULE,
        width=2,
    )
    draw.text((x + 28, panel_top + 20), title, font=label_font, fill=INK)

    row_top = panel_top + 74
    row_height = 174
    string_x = x + 194
    for weight in WEIGHTS:
        font = variable_font(font_path, 32, weight)
        row_bottom = row_top + row_height - 10
        draw.rounded_rectangle(
            (x + 18, row_top, x + panel_width - 18, row_bottom),
            radius=12,
            fill="#FAFBFC",
        )
        draw.text(
            (x + 36, row_top + 18),
            str(weight),
            font=label_font,
            fill=INK,
        )
        draw.text(
            (x + 36, row_top + 63),
            "tnum money",
            font=small_font,
            fill=ACCENT,
        )
        draw.text(
            (x + 36, row_top + 125),
            "default",
            font=small_font,
            fill=MUTED,
        )

        tnum_widths = [
            draw.textlength(text, font=font, features=["tnum"])
            for text in (NARROW, WIDE)
        ]
        if abs(tnum_widths[0] - tnum_widths[1]) > 0.01:
            raise AssertionError(
                f"{title} wght={weight}: tnum widths differ: {tnum_widths}"
            )
        guide_x = string_x + tnum_widths[0]
        draw.line(
            (guide_x, row_top + 46, guide_x, row_top + 111),
            fill=ACCENT,
            width=2,
        )

        draw.text(
            (string_x, row_top + 20),
            NARROW,
            font=font,
            fill=INK,
            features=["tnum"],
        )
        draw.text(
            (string_x, row_top + 58),
            WIDE,
            font=font,
            fill=INK,
            features=["tnum"],
        )

        default_y = row_top + 119
        draw.text((string_x, default_y), NARROW, font=font, fill=MUTED)
        second_x = string_x + 290
        draw.text((second_x, default_y), WIDE, font=font, fill=MUTED)
        for text, start_x in ((NARROW, string_x), (WIDE, second_x)):
            end_x = start_x + draw.textlength(text, font=font)
            draw.ellipse(
                (end_x - 3, default_y + 33, end_x + 3, default_y + 39),
                fill=MUTED,
            )

        row_top += row_height


def draw_ss02_proof(
    draw: ImageDraw.ImageDraw,
    label_font,
    small_font,
) -> None:
    panel_top = 1100
    draw.rounded_rectangle(
        (40, panel_top, WIDTH - 40, HEIGHT - 30),
        radius=20,
        fill=PANEL,
        outline=RULE,
        width=2,
    )
    draw.text(
        (68, panel_top + 20),
        "ss02 · default-off disambiguated lowercase l",
        font=label_font,
        fill=INK,
    )
    draw.text(
        (680, panel_top + 27),
        "identical advances · scoped for IDs, tokens, and code",
        font=small_font,
        fill=MUTED,
    )

    for column_x, title, path in (
        (68, "Upright", DIST / "PivotSans[wght].ttf"),
        (928, "Italic", DIST / "PivotSans-Italic[wght].ttf"),
    ):
        draw.text(
            (column_x, panel_top + 68),
            title,
            font=small_font,
            fill=INK,
        )
        draw.text(
            (column_x + 108, panel_top + 68),
            "default",
            font=small_font,
            fill=MUTED,
        )
        draw.text(
            (column_x + 424, panel_top + 68),
            "ss02",
            font=small_font,
            fill=ACCENT,
        )
        for row, weight in enumerate((300, 400, 700)):
            y = panel_top + 102 + row * 66
            font = variable_font(path, 30, weight)
            default_width = draw.textlength(
                SS02_IDENTIFIER,
                font=font,
                features=["-ss02"],
            )
            alternate_width = draw.textlength(
                SS02_IDENTIFIER,
                font=font,
                features=["ss02"],
            )
            if abs(default_width - alternate_width) > 0.01:
                raise AssertionError(
                    f"{title} wght={weight}: ss02 changed identifier width: "
                    f"{default_width} != {alternate_width}"
                )
            draw.text(
                (column_x, y + 5),
                str(weight),
                font=small_font,
                fill=MUTED,
            )
            draw.text(
                (column_x + 108, y),
                SS02_IDENTIFIER,
                font=font,
                fill=MUTED,
                features=["-ss02"],
            )
            draw.text(
                (column_x + 424, y),
                SS02_IDENTIFIER,
                font=font,
                fill=ACCENT,
                features=["ss02"],
            )

        derivative_font = variable_font(path, 25, 400)
        draw.text(
            (column_x + 108, panel_top + 306),
            SS02_FORMS,
            font=derivative_font,
            fill=ACCENT,
            features=["ss02"],
        )


def main() -> None:
    image = Image.new("RGB", (WIDTH, HEIGHT), BACKGROUND)
    draw = ImageDraw.Draw(image)
    regular = DIST / "static" / "PivotSans-Regular.ttf"
    title_font = ImageFont.truetype(str(regular), 42)
    label_font = ImageFont.truetype(str(regular), 26)
    small_font = ImageFont.truetype(str(regular), 18)

    draw.text((46, 30), "Pivot Sans 1.200", font=title_font, fill=INK)
    draw.text(
        (405, 42),
        "tabular-money proof · matching green guide = matching advance",
        font=label_font,
        fill=MUTED,
    )
    draw_panel(
        draw,
        40,
        "Upright variable",
        DIST / "PivotSans[wght].ttf",
        label_font,
        small_font,
    )
    draw_panel(
        draw,
        920,
        "Italic variable",
        DIST / "PivotSans-Italic[wght].ttf",
        label_font,
        small_font,
    )
    draw_ss02_proof(draw, label_font, small_font)
    image.save(OUTPUT, optimize=True)
    update_release_manifest()
    print(f"wrote {OUTPUT} ({OUTPUT.stat().st_size} bytes)")


if __name__ == "__main__":
    main()
