#!/usr/bin/env python3
"""Build the kicad-tour hero collage from the 6 tile screenshots.

All paths are resolved relative to this script. To regenerate:

    cd plugins/kicad/skills/kicad-tour/hero
    python hero_builder.py

Inputs:
- tiles/01-symbol.png .. 06-3d-board.png — 6 captured KiCad screenshots
- fonts/{FamiljenGrotesk-Bold,Medium,Regular,Satoshi-Regular,Medium}.ttf

Output:
- hero.png (1568×980)

Adom brand tokens are inlined at the top — swap colors there if the brand
shifts. Layout knobs (tile gap, padding, header heights) are also at the top.

The tiles are real KiCad window captures from the RP2040 breakout tour,
not mockups. To recapture: run the tour_runner.py script in the parent
skill dir against the tour-pack-rp2040 pack, then copy the resulting
screenshots into tiles/ with the names above.
"""
from __future__ import annotations
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont

# ── Resolve relative paths from this script's location ─────────────────
HERE = Path(__file__).resolve().parent
TILES = HERE / "tiles"
FONT_DIR = HERE / "fonts"
OUT = HERE / "hero.png"

# ── Brand tokens (Adom) ────────────────────────────────────────────────
TEAL = (0, 184, 176)
TEAL_DARK = (0, 61, 64)
TEAL_DEEP = (0, 33, 36)
WHITE = (255, 255, 255)
MUTED = (174, 184, 188)
BG_TOP = (8, 22, 24)
BG_BOT = (3, 12, 14)

# ── Layout ─────────────────────────────────────────────────────────────
W, H = 1568, 980
PAD = 32

# ── Fonts ──────────────────────────────────────────────────────────────
FG_BOLD = FONT_DIR / "FamiljenGrotesk-Bold.ttf"
FG_MEDIUM = FONT_DIR / "FamiljenGrotesk-Medium.ttf"
FG_REGULAR = FONT_DIR / "FamiljenGrotesk-Regular.ttf"
SAT_REGULAR = FONT_DIR / "Satoshi-Regular.ttf"
SAT_MEDIUM = FONT_DIR / "Satoshi-Medium.ttf"


def font(path: Path, size: int) -> ImageFont.FreeTypeFont:
    return ImageFont.truetype(str(path), size)


# ── Tile manifest ──────────────────────────────────────────────────────
# (filename, label, sublabel, optional flag)
TILES_DEF = [
    ("01-symbol.png", "Symbol", "kicad_install_library + kicad_open_symbol_editor", None),
    ("02-footprint.png", "Footprint", "Install + open the QFN-56 footprint", None),
    ("03-3d-chip.png", "3D Chip", "kicad_open_3d_viewer — model loads from .step", "crop_chip"),
    ("04-schematic.png", "Schematic", "kicad_open_schematic — RP2040 placed on the sheet", None),
    ("05-board.png", "2D Board Layout", "kicad_open_board — footprint on the outline", None),
    ("06-3d-board.png", "3D Board", "editor='pcb' renders the chip on the board", None),
]


def vertical_gradient(top: tuple, bottom: tuple, w: int, h: int) -> Image.Image:
    img = Image.new("RGB", (w, h), top)
    d = ImageDraw.Draw(img)
    for y in range(h):
        f = y / max(1, h - 1)
        c = (
            int(top[0] + (bottom[0] - top[0]) * f),
            int(top[1] + (bottom[1] - top[1]) * f),
            int(top[2] + (bottom[2] - top[2]) * f),
        )
        d.line([(0, y), (w, y)], fill=c)
    return img


def rounded_panel(size: tuple, radius: int, fill: tuple,
                  stroke: tuple | None = None, stroke_w: int = 1) -> Image.Image:
    w, h = size
    img = Image.new("RGBA", (w, h), (0, 0, 0, 0))
    d = ImageDraw.Draw(img)
    d.rounded_rectangle((0, 0, w - 1, h - 1), radius=radius, fill=fill)
    if stroke is not None:
        d.rounded_rectangle((0, 0, w - 1, h - 1), radius=radius, outline=stroke, width=stroke_w)
    return img


def fit_into(img: Image.Image, target_w: int, target_h: int,
             *, crop_chip: bool = False) -> Image.Image:
    """Letterbox-fit `img` into (target_w × target_h)."""
    if crop_chip:
        # Crop tight on the QFN-56 chip in the centre of the 3D board view.
        # The v2 breakout board is 60x25 mm so the chip is small relative to
        # the canvas — tighten the crop window vs the v1 single-resistor pack.
        sw, sh = img.size
        cw, ch = int(sw * 0.26), int(sh * 0.38)
        cx, cy = sw // 2, int(sh * 0.5)
        left = max(0, cx - cw // 2)
        top = max(0, cy - ch // 2)
        img = img.crop((left, top, left + cw, top + ch))

    sw, sh = img.size
    src_ratio = sw / sh
    dst_ratio = target_w / target_h
    if src_ratio > dst_ratio:
        new_w = target_w
        new_h = int(sh * (new_w / sw))
    else:
        new_h = target_h
        new_w = int(sw * (new_h / sh))
    resized = img.resize((new_w, new_h), Image.LANCZOS)
    canvas = Image.new("RGB", (target_w, target_h), TEAL_DEEP)
    canvas.paste(resized, ((target_w - new_w) // 2, (target_h - new_h) // 2))
    return canvas


def draw_tile(canvas: Image.Image, x: int, y: int, w: int, h: int,
              src_path: Path, label: str, sublabel: str, index: int,
              *, crop_chip: bool = False) -> None:
    # Card background
    card = rounded_panel((w, h), 18, fill=(*TEAL_DEEP, 220), stroke=(50, 100, 102), stroke_w=1)
    canvas.paste(card, (x, y), card)

    img_h = int(h * 0.72)
    inner_pad = 12
    img_box = (x + inner_pad, y + inner_pad, x + w - inner_pad, y + inner_pad + img_h)

    src = Image.open(src_path).convert("RGB")
    fitted = fit_into(src, img_box[2] - img_box[0], img_box[3] - img_box[1],
                      crop_chip=crop_chip)
    mask = Image.new("L", fitted.size, 0)
    ImageDraw.Draw(mask).rounded_rectangle(
        (0, 0, fitted.size[0], fitted.size[1]), radius=10, fill=255
    )
    fitted_rgba = fitted.convert("RGBA")
    fitted_rgba.putalpha(mask)
    canvas.paste(fitted_rgba, (img_box[0], img_box[1]), fitted_rgba)

    # Number chip + label + sublabel
    label_y = img_box[3] + 14
    d = ImageDraw.Draw(canvas)
    num_text = f"0{index+1}" if (index + 1) < 10 else str(index + 1)
    num_w, num_h = 36, 20
    num_x = x + inner_pad
    num_y = label_y
    d.rounded_rectangle((num_x, num_y, num_x + num_w, num_y + num_h), radius=10, fill=TEAL)
    num_font = font(FG_BOLD, 12)
    bbox = d.textbbox((0, 0), num_text, font=num_font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    d.text((num_x + (num_w - tw) // 2, num_y + (num_h - th) // 2 - 1),
           num_text, fill=TEAL_DEEP, font=num_font)
    d.text((num_x + num_w + 10, num_y - 2), label, fill=WHITE, font=font(FG_BOLD, 20))
    d.text((num_x, num_y + num_h + 10), sublabel, fill=MUTED, font=font(SAT_REGULAR, 12))


def main() -> int:
    base = vertical_gradient(BG_TOP, BG_BOT, W, H).convert("RGBA")
    d = ImageDraw.Draw(base)

    # ── Header ─────────────────────────────────────────────────────────
    badge_x, badge_y = PAD, PAD
    badge_w, badge_h = 70, 26
    d.rounded_rectangle((badge_x, badge_y, badge_x + badge_w, badge_y + badge_h),
                        radius=13, fill=TEAL)
    bf = font(FG_BOLD, 14)
    bb = d.textbbox((0, 0), "ADOM", font=bf)
    bw, bh = bb[2] - bb[0], bb[3] - bb[1]
    d.text((badge_x + (badge_w - bw) // 2, badge_y + (badge_h - bh) // 2 - 1),
           "ADOM", fill=TEAL_DEEP, font=bf)
    d.text((badge_x + badge_w + 14, badge_y + 4), "DESKTOP  ·  KICAD BRIDGE",
           fill=MUTED, font=font(SAT_MEDIUM, 13))

    headline = "Drive KiCad from anywhere."
    d.text((PAD, badge_y + badge_h + 14), headline,
           fill=WHITE, font=font(FG_BOLD, 56))

    sub_a = "Send a custom symbol, footprint and 3D model into KiCad on the user's laptop."
    sub_b = "Open the schematic. Place the board. Render in 3D. Export gerbers to JLCPCB / InstaPCB."
    d.text((PAD, badge_y + badge_h + 14 + 64), sub_a,
           fill=(220, 230, 232), font=font(SAT_REGULAR, 19))
    d.text((PAD, badge_y + badge_h + 14 + 64 + 28), sub_b,
           fill=(180, 195, 198), font=font(SAT_REGULAR, 19))

    chip_text = "8 verbs · 90 seconds · 1 chip"
    cf = font(FG_BOLD, 14)
    cb = d.textbbox((0, 0), chip_text, font=cf)
    cw, ch = cb[2] - cb[0], cb[3] - cb[1]
    chip_pad_x, chip_pad_y = 18, 11
    chip_x = W - PAD - cw - 2 * chip_pad_x
    chip_y = PAD + 4
    d.rounded_rectangle(
        (chip_x, chip_y, chip_x + cw + 2 * chip_pad_x, chip_y + ch + 2 * chip_pad_y),
        radius=16, fill=(*TEAL_DARK, 255), outline=TEAL, width=1,
    )
    d.text((chip_x + chip_pad_x, chip_y + chip_pad_y - 1), chip_text,
           fill=TEAL, font=cf)

    # ── Tiles 2×3 grid ────────────────────────────────────────────────
    grid_top = badge_y + badge_h + 14 + 64 + 28 + 38
    gap = 22
    tile_w = (W - 2 * PAD - 2 * gap) // 3
    tile_h = (H - grid_top - PAD - gap - 80) // 2

    for i, (fname, label, sublabel, flag) in enumerate(TILES_DEF):
        col, row = i % 3, i // 3
        x = PAD + col * (tile_w + gap)
        y = grid_top + row * (tile_h + gap)
        draw_tile(base, x, y, tile_w, tile_h,
                  src_path=TILES / fname,
                  label=label, sublabel=sublabel, index=i,
                  crop_chip=(flag == "crop_chip"))

    # ── Footer ────────────────────────────────────────────────────────
    foot_y = grid_top + 2 * tile_h + gap + 18
    flow = "send symbol  →  send footprint  →  3D-verify chip  →  schematic  →  layout  →  3D board  →  gerbers"
    d.text((PAD, foot_y), flow, fill=(190, 205, 208), font=font(SAT_MEDIUM, 16))
    cta = "adom-desktop  kicad_*  ·  v1.8.97  ·  Bridge v0.8.5"
    cf2 = font(FG_BOLD, 14)
    cb2 = d.textbbox((0, 0), cta, font=cf2)
    cw2 = cb2[2] - cb2[0]
    d.text((W - PAD - cw2, foot_y), cta, fill=TEAL, font=cf2)

    base.convert("RGB").save(OUT, optimize=True)
    print(f"wrote {OUT} ({OUT.stat().st_size:,} bytes, {W}x{H})")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
