#!/usr/bin/env python3
"""
Generate the full favicon + app-icon set from the SVG masters in
public/branding/masters/.

Outputs (all in public/):
  favicon.ico                 multi-resolution (16, 32, 48)
  favicon-16x16.png           browser tab (small)
  favicon-32x32.png           browser tab (retina)
  favicon-48x48.png           Windows site icons
  apple-touch-icon.png        180×180 — iOS home screen
  android-chrome-192x192.png  192×192 — Android maskable
  android-chrome-512x512.png  512×512 — Android maskable / splash
  icon-192.png                alias of android-chrome-192 (manifest backwards-compat)
  icon-512.png                alias of android-chrome-512 (manifest backwards-compat)
  mstile-150x150.png          150×150 — Windows tile
  safari-pinned-tab.svg       monochrome SVG (mask-icon)
  og-image.png                regenerated default (1200×630, identical to og-default-v2.png)

For favicons (16/32/48), the bare crown silhouette is too detailed to read
clearly. We use a simplified version with no gem dots and a stronger sparkle
shape so the icon stays legible in browser tabs. For app icons (180+), we use
the full maskable variant (purple square backplate + white crown with amber
accents).

Usage:
    python3 scripts/branding/generate_favicons.py
"""

from __future__ import annotations

import struct
import io
from pathlib import Path

import cairosvg
from PIL import Image

REPO_ROOT = Path(__file__).resolve().parents[2]
PUBLIC_DIR = REPO_ROOT / "public"
MASTERS_DIR = PUBLIC_DIR / "branding" / "masters"

PURPLE = "#7C3AED"

# ──────────────────────────────────────────────────────────────────────────
# Small-size simplified icon. At 16/32 px, the gem dots and band stripes
# disappear into noise. We render a cleaner mark: full-bleed purple
# rounded backplate + white crown + amber sparkle (no band, no gems).
# ──────────────────────────────────────────────────────────────────────────
SIMPLIFIED_ICON_SVG = """<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
  <rect width="64" height="64" rx="12" fill="#7C3AED"/>
  <g transform="translate(8, 8) scale(0.4)">
    <path d="M16 96 L16 76 L28 56 L40 76 L60 36 L80 76 L92 20 L104 76 L104 96 Z" fill="#FFFFFF"/>
    <path d="M92 4 C 93 8 93.5 8.5 97 10 C 93.5 11.5 93 12 92 16 C 91 12 90.5 11.5 87 10 C 90.5 8.5 91 8 92 4 Z" fill="#FCD34D"/>
  </g>
</svg>"""

# Maskable icon for app surfaces (180+).
def maskable_svg() -> str:
    return (MASTERS_DIR / "icon-maskable.svg").read_text(encoding="utf-8")

# Monochrome silhouette for Safari pinned-tab (single-ink, no fill required).
def mono_black_svg() -> str:
    return (MASTERS_DIR / "icon-mono-black.svg").read_text(encoding="utf-8")


def render_png(svg: str, *, size: int, out: Path) -> None:
    cairosvg.svg2png(
        bytestring=svg.encode("utf-8"),
        write_to=str(out),
        output_width=size,
        output_height=size,
    )
    print(f"  → {out.relative_to(REPO_ROOT)}  {out.stat().st_size/1024:.1f} KB  ({size}×{size})")


def write_ico(png_paths: list[Path], out: Path) -> None:
    """Build a multi-resolution .ico from a list of PNG sources."""
    images = [Image.open(p) for p in png_paths]
    # Pillow can write ICO with multiple sizes from a single base image, but
    # we have already-rendered PNGs at the right sizes, so save the largest
    # and pass the size list.
    base = max(images, key=lambda im: im.size[0])
    sizes = [im.size for im in images]
    base.save(out, format="ICO", sizes=sizes)
    print(f"  → {out.relative_to(REPO_ROOT)}  {out.stat().st_size/1024:.1f} KB  (multi-res {sizes})")


def main() -> None:
    print("Rendering favicon / app-icon set →", PUBLIC_DIR)

    # 1. Small favicons — simplified mark for legibility
    fav16 = PUBLIC_DIR / "favicon-16x16.png"
    fav32 = PUBLIC_DIR / "favicon-32x32.png"
    fav48 = PUBLIC_DIR / "favicon-48x48.png"
    render_png(SIMPLIFIED_ICON_SVG, size=16, out=fav16)
    render_png(SIMPLIFIED_ICON_SVG, size=32, out=fav32)
    render_png(SIMPLIFIED_ICON_SVG, size=48, out=fav48)

    # 2. favicon.ico (multi-resolution: 16/32/48)
    write_ico([fav16, fav32, fav48], PUBLIC_DIR / "favicon.ico")

    # 3. App icons — full maskable variant
    maskable = maskable_svg()
    render_png(maskable, size=180, out=PUBLIC_DIR / "apple-touch-icon.png")
    render_png(maskable, size=192, out=PUBLIC_DIR / "android-chrome-192x192.png")
    render_png(maskable, size=512, out=PUBLIC_DIR / "android-chrome-512x512.png")
    render_png(maskable, size=150, out=PUBLIC_DIR / "mstile-150x150.png")

    # 4. Backwards-compat aliases for icon-192/512.png (manifest references)
    render_png(maskable, size=192, out=PUBLIC_DIR / "icon-192.png")
    render_png(maskable, size=512, out=PUBLIC_DIR / "icon-512.png")

    # 5. Save the simplified-icon master so it's version-controlled too
    (MASTERS_DIR / "icon-simplified.svg").write_text(SIMPLIFIED_ICON_SVG, encoding="utf-8")
    print(f"  → {(MASTERS_DIR / 'icon-simplified.svg').relative_to(REPO_ROOT)}  (master)")

    # 6. Safari pinned-tab — monochrome SVG, copy from master
    (PUBLIC_DIR / "safari-pinned-tab.svg").write_text(
        mono_black_svg(), encoding="utf-8"
    )
    print(f"  → public/safari-pinned-tab.svg  (monochrome)")

    # 7. Default OG image — copy from generated og-default-v2.png
    default_og = PUBLIC_DIR / "og" / "og-default-v2.png"
    if default_og.exists():
        out = PUBLIC_DIR / "og-image.png"
        out.write_bytes(default_og.read_bytes())
        print(f"  → public/og-image.png  {out.stat().st_size/1024:.1f} KB  (default fallback)")
    else:
        print("  (skipped og-image.png — run generate_og_images.py first)")

    print("Done.")


if __name__ == "__main__":
    main()
