from __future__ import annotations

from collections import deque
from pathlib import Path

from PIL import Image


ROOT = Path(__file__).resolve().parents[1]
SOURCE_ROOT = Path("D:/")
OUT_ROOT = ROOT / "public" / "assets" / "brain"
LANCZOS = getattr(getattr(Image, "Resampling", Image), "LANCZOS")


ASSETS = {
    "memory/bread.png": "ChatGPT Image 2026年7月23日 21_31_30 (1).png",
    "memory/carrot.png": "ChatGPT Image 2026年7月23日 21_31_32 (2).png",
    "memory/coffee.png": "ChatGPT Image 2026年7月23日 21_31_34 (4).png",
    "memory/cookie.png": "ChatGPT Image 2026年7月23日 21_31_35 (5).png",
    "memory/egg.png": "ChatGPT Image 2026年7月23日 21_31_36 (6).png",
    "memory/fish.png": "ChatGPT Image 2026年7月23日 21_31_38 (7).png",
    "memory/orange.png": "ChatGPT Image 2026年7月23日 21_31_39 (8).png",
    "memory/cheese.png": "ChatGPT Image 2026年7月23日 21_31_40.png",
    "planes/teal.png": "ChatGPT Image 2026年7月23日 21_31_44 (9).png",
    "planes/coral.png": "ChatGPT Image 2026年7月23日 21_31_45 (10).png",
    "symbols/camera.png": "ChatGPT Image 2026年7月23日 21_40_52 (1).png",
    "symbols/sun.png": "ChatGPT Image 2026年7月23日 21_40_52 (2).png",
    "symbols/squares.png": "ChatGPT Image 2026年7月23日 21_40_53 (3).png",
    "symbols/lock.png": "ChatGPT Image 2026年7月23日 21_40_53 (4).png",
    "symbols/lightning.png": "ChatGPT Image 2026年7月23日 21_40_53 (5).png",
    "symbols/moon.png": "ChatGPT Image 2026年7月23日 21_40_53 (6).png",
    "symbols/gear.png": "ChatGPT Image 2026年7月23日 21_40_53 (7).png",
    "symbols/star.png": "ChatGPT Image 2026年7月23日 21_40_53 (8).png",
    "symbols/puzzle.png": "ChatGPT Image 2026年7月23日 21_40_53 (9).png",
    "symbols/coffee.png": "ChatGPT Image 2026年7月23日 21_40_53 (10).png",
}


def has_real_alpha(image: Image.Image) -> bool:
    if "A" not in image.getbands():
        return False
    alpha = image.getchannel("A")
    lo, hi = alpha.getextrema()
    return lo < 255 and hi == 255


def remove_generated_checkerboard(image: Image.Image) -> Image.Image:
    rgba = image.convert("RGBA")
    rgba.thumbnail((720, 720), LANCZOS)
    pixels = rgba.load()
    width, height = rgba.size

    def is_background(x: int, y: int) -> bool:
        red, green, blue, _ = pixels[x, y]
        high = max(red, green, blue)
        low = min(red, green, blue)
        return low >= 218 and high - low <= 18

    # Flood only from the canvas edge. This removes the connected checkerboard
    # without punching holes into pale objects such as the teal plane or egg.
    queue: deque[tuple[int, int]] = deque()
    visited = bytearray(width * height)
    for x in range(width):
        queue.append((x, 0))
        queue.append((x, height - 1))
    for y in range(height):
        queue.append((0, y))
        queue.append((width - 1, y))

    while queue:
        x, y = queue.popleft()
        offset = y * width + x
        if visited[offset] or not is_background(x, y):
            continue
        visited[offset] = 1
        if x:
            queue.append((x - 1, y))
        if x + 1 < width:
            queue.append((x + 1, y))
        if y:
            queue.append((x, y - 1))
        if y + 1 < height:
            queue.append((x, y + 1))

    for y in range(height):
        for x in range(width):
            red, green, blue, _ = pixels[x, y]
            alpha = 0 if visited[y * width + x] else 255
            pixels[x, y] = (red, green, blue, alpha)

    bounds = rgba.getbbox()
    if bounds:
        rgba = rgba.crop(bounds)
    return rgba


def copy_or_convert(source: Path, destination: Path) -> None:
    destination.parent.mkdir(parents=True, exist_ok=True)
    with Image.open(source) as image:
        if has_real_alpha(image):
            prepared = image.convert("RGBA")
            bounds = prepared.getbbox()
            if bounds:
                prepared = prepared.crop(bounds)
            prepared.thumbnail((720, 720), LANCZOS)
        else:
            prepared = remove_generated_checkerboard(image)
        prepared.save(destination, optimize=True)


def main() -> None:
    missing: list[str] = []
    for output, source_name in ASSETS.items():
        source = SOURCE_ROOT / source_name
        destination = OUT_ROOT / output
        if not source.exists():
            missing.append(source_name)
            continue
        copy_or_convert(source, destination)
    if missing:
        raise SystemExit("Missing assets:\n" + "\n".join(missing))


if __name__ == "__main__":
    main()
