#!/usr/bin/env python
"""
Download CC0 PBR texture sets from ambientCG and resize them to 512px JPEGs
suitable for the house-plan-maker 3D view. Outputs land in
apps/client/public/textures/{floors,walls}/<slug>/{color,normal,roughness}.jpg

Texture credit: ambientCG (https://ambientcg.com), CC0 1.0 Universal.

Run from repo root:
    py -3 scripts/fetch-textures.py

Re-running is idempotent — files are skipped if they already exist.
"""

import io
import os
import sys
import urllib.request
import zipfile
from pathlib import Path

try:
    from PIL import Image
except ImportError:
    print("ERROR: PIL/Pillow is required. Install with: py -3 -m pip install pillow", file=sys.stderr)
    sys.exit(1)

REPO_ROOT = Path(__file__).resolve().parent.parent
OUT_ROOT = REPO_ROOT / "apps" / "client" / "public" / "textures"
TARGET_SIZE = 512

# Map our enum values to ambientCG asset ids. The names follow the
# Camera/Wood/Tile/etc. categories on https://ambientcg.com.
FLOORS = {
    # FloorType -> ambientCG asset
    "CONCRETE": "Concrete034",
    "WOOD_LIGHT": "WoodFloor043",
    "WOOD_MEDIUM": "WoodFloor041",
    "WOOD_DARK": "WoodFloor051",
    "WOOD_HERRINGBONE": "WoodFloor057",
    "TILE_WHITE": "Tiles074",
    "TILE_GRAY": "Tiles101",
    "LAMINATE": "WoodFloor044",
}

WALLS = {
    # WallFinish -> ambientCG asset (PAINT skips textures, uses wallColor)
    "PLASTER": "Plaster001",
    "BRICK": "Bricks023",
    "CONCRETE": "Concrete019",
    "WOOD_PANEL": "WoodSiding001",
    "WALLPAPER": "Fabric030",
}

# Maps we want from each set. ambientCG file naming: <Asset>_1K-JPG_<Map>.jpg
MAPS = {
    "color": "Color",
    "normal": "NormalGL",
    "roughness": "Roughness",
}


def download_zip(asset_id: str) -> bytes:
    url = f"https://ambientcg.com/get?file={asset_id}_1K-JPG.zip"
    print(f"  fetching {url}")
    req = urllib.request.Request(url, headers={"User-Agent": "house-plan-maker/1.0"})
    with urllib.request.urlopen(req, timeout=60) as resp:
        return resp.read()


def extract_and_resize(zip_bytes: bytes, asset_id: str, out_dir: Path) -> bool:
    out_dir.mkdir(parents=True, exist_ok=True)
    try:
        zf = zipfile.ZipFile(io.BytesIO(zip_bytes))
    except zipfile.BadZipFile:
        # Server returned an HTML error page, not a zip.
        print(f"  ERROR: {asset_id} did not return a zip — preview: {zip_bytes[:120]!r}")
        return False

    names = {n.lower(): n for n in zf.namelist()}
    success = True

    for out_name, ambient_map in MAPS.items():
        out_path = out_dir / f"{out_name}.jpg"
        if out_path.exists():
            print(f"  skip (exists): {out_path.relative_to(REPO_ROOT)}")
            continue
        # Find the matching file in the zip (case-insensitive substring match).
        needle = f"_{ambient_map}.jpg".lower()
        match_lower = next((k for k in names if k.endswith(needle)), None)
        if not match_lower:
            print(f"  WARN: no {ambient_map} map in {asset_id}")
            success = False
            continue
        with zf.open(names[match_lower]) as src:
            img = Image.open(src)
            img = img.convert("RGB")
            img = img.resize((TARGET_SIZE, TARGET_SIZE), Image.LANCZOS)
            img.save(out_path, "JPEG", quality=82, optimize=True)
        print(f"  wrote {out_path.relative_to(REPO_ROOT)} ({out_path.stat().st_size // 1024} KB)")

    return success


def fetch_set(category: str, label: str, asset_id: str) -> None:
    out_dir = OUT_ROOT / category / label.lower()
    print(f"[{category}/{label}] -> {asset_id}")
    # Skip whole asset if all three target files already exist.
    if all((out_dir / f"{m}.jpg").exists() for m in MAPS):
        print(f"  all maps already present, skipping fetch")
        return
    try:
        zip_bytes = download_zip(asset_id)
    except Exception as e:
        print(f"  ERROR fetching {asset_id}: {e}")
        return
    extract_and_resize(zip_bytes, asset_id, out_dir)


def main() -> None:
    print(f"writing to {OUT_ROOT}")
    OUT_ROOT.mkdir(parents=True, exist_ok=True)

    for label, asset_id in FLOORS.items():
        fetch_set("floors", label, asset_id)

    for label, asset_id in WALLS.items():
        fetch_set("walls", label, asset_id)

    print("done.")


if __name__ == "__main__":
    main()
