"""
FreeExile Banana AI Asset Production Pipeline (October 2026).
Processes native Gemini-generated concepts into production-ready game assets:
1. 4 Canonical Climax Bosses (512x512 RGBA + Tangent-Space Normal Maps)
2. 2 Narrative Act Splash Illustrations (1024x1024 RGBA)
3. 2 Endgame & Economy Props (512x512 RGBA + Tangent-Space Normal Maps)
Strictly adheres to Power-of-Two, Blue > 128.0 normal maps, and clean alpha borders.
"""

from __future__ import annotations

import os
import sys
from pathlib import Path
from typing import Dict, List, Tuple

import numpy as np
from PIL import Image, ImageFilter

REPO_ROOT = Path(__file__).resolve().parent.parent.parent
if str(REPO_ROOT) not in sys.path:
    sys.path.insert(0, str(REPO_ROOT))

BRAIN_DIR = Path(r"C:\Users\Admin\.gemini\antigravity\brain\59bafa97-39ad-4b55-8651-c37859a91ca7")
CLIENT_ASSETS = REPO_ROOT / "client" / "webapp" / "assets"

from tools.asset_pipeline.m4_normal_utils import compute_tangent_normal_map
from tools.asset_pipeline.texture_compressor import compress_to_webp


def find_latest_artifact(prefix: str) -> Path | None:
    matches = sorted(BRAIN_DIR.glob(f"{prefix}*.jpg"))
    return matches[-1] if matches else None


def clean_black_background(img: Image.Image, threshold: int = 18, soft_range: float = 30.0) -> Image.Image:
    """Removes dark studio background with smooth anti-aliased alpha edge."""
    rgba = img.convert("RGBA")
    arr = np.array(rgba, dtype=np.float32)
    # Intensity based on max RGB
    rgb_max = np.max(arr[:, :, :3], axis=2)
    
    alpha = np.clip((rgb_max - threshold) / soft_range * 255.0, 0.0, 255.0)
    arr[:, :, 3] = alpha
    result = Image.fromarray(arr.astype(np.uint8), mode="RGBA")
    return result


def process_entity_sprite(src_path: Path, dest_path: Path, target_size: Tuple[int, int] = (512, 512)) -> None:
    """Processes transparent isometric sprite with PBR tangent normal map."""
    with Image.open(src_path) as src:
        cleaned = clean_black_background(src, threshold=15, soft_range=25.0)
        # Bounding box crop if isolated
        bbox = cleaned.split()[-1].getbbox()
        if bbox:
            # Add subtle padding
            w, h = cleaned.size
            pad = 10
            x0 = max(0, bbox[0] - pad)
            y0 = max(0, bbox[1] - pad)
            x1 = min(w, bbox[2] + pad)
            y1 = min(h, bbox[3] + pad)
            cropped = cleaned.crop((x0, y0, x1, y1))
        else:
            cropped = cleaned

        # Aspect-ratio preserving resize into square target_size
        cw, ch = cropped.size
        scale = min(target_size[0] / cw, target_size[1] / ch) * 0.95
        new_w = int(cw * scale)
        new_h = int(ch * scale)
        resized = cropped.resize((new_w, new_h), Image.Resampling.LANCZOS)

        canvas = Image.new("RGBA", target_size, (0, 0, 0, 0))
        offset_x = (target_size[0] - new_w) // 2
        offset_y = (target_size[1] - new_h) // 2
        canvas.paste(resized, (offset_x, offset_y), resized)

    dest_path.parent.mkdir(parents=True, exist_ok=True)
    canvas.save(dest_path, "PNG")
    compress_to_webp(dest_path, quality=85)

    # Generate Tangent-Space Normal Map
    normal_img = compute_tangent_normal_map(canvas, strength=2.8)
    normal_path = dest_path.parent / f"{dest_path.stem}_normal.png"
    normal_img.save(normal_path, "PNG")
    compress_to_webp(normal_path, quality=85)
    print(f"[OK] Processed {dest_path.name} & {normal_path.name} (with WebP)")


def process_splash_art(src_path: Path, dest_path: Path, target_size: Tuple[int, int] = (1024, 1024)) -> None:
    """Processes full-frame splash art with power-of-two 1024x1024 dimensions."""
    with Image.open(src_path) as src:
        resized = src.resize(target_size, Image.Resampling.LANCZOS).convert("RGBA")
    dest_path.parent.mkdir(parents=True, exist_ok=True)
    resized.save(dest_path, "PNG")
    compress_to_webp(dest_path, quality=85)
    print(f"[OK] Processed Splash: {dest_path.name} (with WebP)")


def run_pipeline() -> None:
    print("=== FreeExile Banana Asset Production Pipeline ===")
    
    # 1. Climax & Mythic Bosses
    bosses = [
        ("dune_bone_scorpion", CLIENT_ASSETS / "monsters" / "boss_dune_bone_scorpion.png", (512, 512)),
        ("primal_blood_ape", CLIENT_ASSETS / "monsters" / "boss_primal_blood_ape.png", (512, 512)),
        ("strand_executioner_boss", CLIENT_ASSETS / "monsters" / "boss_strand_executioner.png", (512, 512)),
        ("scourge_lord_boss", CLIENT_ASSETS / "monsters" / "boss_forsaken_scourge_lord.png", (512, 512)),
        ("putrid_ancient_corpse", CLIENT_ASSETS / "monsters" / "boss_putrid_ancient_corpse.png", (512, 512)),
        ("abyssal_ice_dragon", CLIENT_ASSETS / "monsters" / "boss_abyssal_ice_dragon.png", (512, 512)),
        ("hellfire_primal_chimera", CLIENT_ASSETS / "monsters" / "boss_hellfire_primal_chimera.png", (512, 512)),
    ]
    for prefix, out_file, size in bosses:
        src = find_latest_artifact(prefix)
        if src:
            process_entity_sprite(src, out_file, size)
        else:
            print(f"[WARN] Missing artifact for {prefix}")

    # 2. Splash Art Chapters
    splashes = [
        ("splash_chapter4_titan", CLIENT_ASSETS / "illustrations" / "splash_chapter4_titan.png"),
        ("splash_chapter5_sovereign", CLIENT_ASSETS / "illustrations" / "splash_chapter5_sovereign.png"),
    ]
    for prefix, out_file in splashes:
        src = find_latest_artifact(prefix)
        if src:
            process_splash_art(src, out_file, (1024, 1024))
        else:
            print(f"[WARN] Missing artifact for {prefix}")

    # 3. Environment & Props
    props = [
        ("astral_map_device", CLIENT_ASSETS / "environment" / "astral_map_device_altar.png", (512, 512)),
        ("outcast_bazaar_vault", CLIENT_ASSETS / "environment" / "outcast_bazaar_vault.png", (512, 512)),
        ("blood_bone_altar", CLIENT_ASSETS / "environment" / "blood_bone_altar.png", (512, 512)),
        ("primordial_blacksmith_forge", CLIENT_ASSETS / "environment" / "primordial_blacksmith_forge.png", (512, 512)),
        ("strand_shipwreck_hulk", CLIENT_ASSETS / "environment" / "strand_shipwreck_hulk.png", (512, 512)),
        ("monolith_soul_shrine", CLIENT_ASSETS / "environment" / "prop_monolith_soul_shrine.png", (512, 512)),
        ("crypt_dungeon_portal", CLIENT_ASSETS / "environment" / "prop_crypt_dungeon_portal.png", (512, 512)),
        ("outlaw_wilderness_tavern", CLIENT_ASSETS / "environment" / "building_outlaw_tavern.png", (512, 512)),
        ("dragon_fossil_bones", CLIENT_ASSETS / "environment" / "prop_dragon_fossil_bones.png", (512, 512)),
    ]
    for prefix, out_file, size in props:
        src = find_latest_artifact(prefix)
        if src:
            process_entity_sprite(src, out_file, size)
        else:
            print(f"[WARN] Missing artifact for {prefix}")

    # 4. Currencies, Divine Weapons & Skill Relics
    items = [
        ("blood_soul_orb", CLIENT_ASSETS / "currencies" / "currency_blood_soul_orb.png", (256, 256)),
        ("primal_blood_mirror", CLIENT_ASSETS / "currencies" / "currency_primal_blood_mirror.png", (256, 256)),
        ("demon_infusion_orb", CLIENT_ASSETS / "currencies" / "currency_demon_infusion_orb.png", (256, 256)),
        ("nether_bone_nail", CLIENT_ASSETS / "currencies" / "currency_nether_bone_nail.png", (256, 256)),
        ("dragonbone_maw_axe", CLIENT_ASSETS / "weapons" / "wpn_dragonbone_maw_axe.png", (512, 512)),
        ("azure_wind_dao", CLIENT_ASSETS / "weapons" / "wpn_azure_wind_dao.png", (512, 512)),
        ("bone_spike_bow", CLIENT_ASSETS / "weapons" / "wpn_bone_spike_bow.png", (512, 512)),
        ("blood_reaper_scythe", CLIENT_ASSETS / "weapons" / "wpn_blood_reaper_scythe.png", (512, 512)),
        ("demon_bone_shield", CLIENT_ASSETS / "weapons" / "wpn_demon_bone_shield.png", (512, 512)),
        ("fire_dragon_staff", CLIENT_ASSETS / "weapons" / "wpn_fire_dragon_staff.png", (512, 512)),
        ("phantom_dash_relic", CLIENT_ASSETS / "skills" / "relic_phantom_ghost_dash.png", (256, 256)),
    ]
    for prefix, out_file, size in items:
        src = find_latest_artifact(prefix)
        if src:
            process_entity_sprite(src, out_file, size)
        else:
            print(f"[WARN] Missing artifact for {prefix}")

    # 5. Playable Hero Characters
    characters = [
        ("feral_berserker_hero", CLIENT_ASSETS / "characters" / "hero_feral_berserker.png", (512, 512)),
        ("shadow_blade_assassin", CLIENT_ASSETS / "characters" / "hero_shadow_assassin.png", (512, 512)),
        ("glacial_frost_lancer", CLIENT_ASSETS / "characters" / "hero_glacial_lancer.png", (512, 512)),
    ]
    for prefix, out_file, size in characters:
        src = find_latest_artifact(prefix)
        if src:
            process_entity_sprite(src, out_file, size)
        else:
            print(f"[WARN] Missing artifact for {prefix}")

    print("=== Pipeline Complete ===")


if __name__ == "__main__":
    run_pipeline()
