#!/usr/bin/env python3
"""
Convert PNG icons to C headers (RGB565 uint16_t arrays) for TFT_eSPI pushImage.

Usage:
    python3 tools/png_to_c_icon.py
    (run from the CodexBar-ESP32 root)

Output files are written to codexbar_esp32/icon_*.h and are included by the
Arduino sketch.  Transparent pixels (alpha < 128) are mapped to ICON_TRANSPARENT
so tft.pushImage can skip them and show the display background through.
"""
import os
import sys

try:
    from PIL import Image
except ImportError:
    print("Pillow not found — run: pip install pillow  (or use the project venv)")
    sys.exit(1)

# Must match COL_BG in config.h: RGB565(28, 28, 30) = 0x18E3.
# Any source pixel with alpha < 128 is replaced with this value.
TRANSPARENT = 0x18E3

ICON_SIZE = 32  # device pixels; all three icons share this size

ICONS = [
    ("claude",  "claude.png",  "CLAUDE_ICON"),
    ("openai",  "openai.png",  "CODEX_ICON"),
    ("gemini",  "gemini.png",  "GEMINI_ICON"),
]


def rgb_to_rgb565(r: int, g: int, b: int) -> int:
    return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)


def convert(src: str, dst: str, var_name: str, size: int = ICON_SIZE) -> None:
    img = Image.open(src).convert("RGBA").resize((size, size), Image.LANCZOS)
    pixels = []
    for y in range(size):
        for x in range(size):
            r, g, b, a = img.getpixel((x, y))
            pixels.append(TRANSPARENT if a < 128 else rgb_to_rgb565(r, g, b))

    with open(dst, "w") as f:
        f.write(f"// Auto-generated by tools/png_to_c_icon.py — do not edit.\n")
        f.write(f"// Source: {os.path.basename(src)}  |  {size}×{size} px  |  "
                f"transparent key: 0x{TRANSPARENT:04X}\n")
        f.write("#pragma once\n")
        f.write(f"static const uint16_t {var_name}[{size * size}] PROGMEM = {{\n")
        for i, px in enumerate(pixels):
            if i % 16 == 0:
                f.write("  ")
            f.write(f"0x{px:04X},")
            f.write("\n" if i % 16 == 15 else " ")
        f.write("};\n")

    print(f"  {dst}  ({size}×{size}, {size*size*2} bytes)")


def main() -> None:
    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    icons_dir    = os.path.join(root, "assets", "icons")
    out_dir      = os.path.join(root, "codexbar_esp32")

    print(f"Generating {ICON_SIZE}×{ICON_SIZE} RGB565 icon headers …")
    missing = []
    for key, filename, var_name in ICONS:
        src = os.path.join(icons_dir, filename)
        dst = os.path.join(out_dir, f"icon_{key}.h")
        if os.path.exists(src):
            convert(src, dst, var_name)
        else:
            print(f"  SKIPPING {src} (not found)")
            missing.append(filename)

    if missing:
        print(f"\nNote: {len(missing)} icon(s) missing; those providers will use a text fallback.")
    else:
        print("\nDone.")


if __name__ == "__main__":
    main()
