"""
render_heads.py
Fetches isometric 3D head PNGs from mc-heads.net using texture values
from the head_data cache (generated by upload_skins.py).

Usage:
  python render_heads.py

Input:  output/head_data/llama.json
Output: output/renders/<variant>.png

Resume-safe: already downloaded renders are skipped.
Run upload_skins.py first to populate the head_data cache.
"""

import time
import pathlib
import json
import base64
import urllib.request
import urllib.error

SCRIPT_DIR  = pathlib.Path(__file__).parent
DATA_DIR    = SCRIPT_DIR / "output" / "head_data"
OUTPUT_DIR  = SCRIPT_DIR / "output" / "renders"
CACHE_PATH  = DATA_DIR / "llama.json"

MCHEADS_URL = "https://mc-heads.net/head/{hash}/{size}"
RENDER_SIZE = 128
DELAY       = 0.5  # seconds between requests


def texture_to_hash(texture_value: str) -> str:
    """Decode Base64 texture value and extract the Mojang texture hash."""
    padded = texture_value + "=" * (-len(texture_value) % 4)
    decoded = json.loads(base64.b64decode(padded).decode("utf-8"))
    url = decoded["textures"]["SKIN"]["url"]
    return url.rsplit("/", 1)[-1]


def fetch_render(texture_value: str, out_path: pathlib.Path, size: int = RENDER_SIZE) -> bool:
    skin_hash = texture_to_hash(texture_value)
    url = MCHEADS_URL.format(hash=skin_hash, size=size)
    req = urllib.request.Request(url, headers={"User-Agent": "jodeks-datapacks/mob-heads"})
    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            data = resp.read()
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_bytes(data)
        return True
    except urllib.error.HTTPError as e:
        print(f"    HTTP {e.code}: {url}")
        return False
    except Exception as e:
        print(f"    ERROR: {e}")
        return False


def main():
    if not CACHE_PATH.exists():
        print(f"ERROR: {CACHE_PATH} not found — run upload_skins.py first")
        raise SystemExit(1)

    entries = json.loads(CACHE_PATH.read_text(encoding="utf-8"))
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    print(f"Fetching renders for 'llama' ({len(entries)} variants)...")

    fetched = 0
    skipped = 0
    failed  = 0

    for i, entry in enumerate(entries, 1):
        variant       = entry["variant"]
        texture_value = entry["texture"]
        out_path      = OUTPUT_DIR / f"{variant}.png"

        if out_path.exists():
            print(f"  [{i}/{len(entries)}] {variant} — skipped (exists)")
            skipped += 1
            continue

        ok = fetch_render(texture_value, out_path)
        if ok:
            print(f"  [{i}/{len(entries)}] {variant} — fetched ✓")
            fetched += 1
        else:
            print(f"  [{i}/{len(entries)}] {variant} — failed")
            failed += 1

        if i < len(entries):
            time.sleep(DELAY)

    print(f"\nDone. fetched={fetched} skipped={skipped} failed={failed}")
    print(f"Renders in: {OUTPUT_DIR}")


if __name__ == "__main__":
    main()
