"""
Genera el logo final de Leonex desde el PNG original cargado por el usuario.

Preserva la silueta del logo original, limpia el fondo de tablero, recolorea
los pixeles oscuros a aguamarina y exporta un PNG estable para el dashboard.
"""

from __future__ import annotations

from pathlib import Path

from PIL import Image, ImageEnhance, ImageFilter


ROOT = Path(__file__).resolve().parents[1]
ASSETS_DIR = ROOT / "assets"
OUTPUT_PATH = ASSETS_DIR / "Leonex-logo.png"
EXCLUDE = {
    "Leonex-logo.png",
    "Leonex-logo-polished.png",
}

AQUA = (86, 240, 223)
WHITE = (255, 255, 255)
CANVAS_SIZE = 768
LOGO_SIZE = 650
FINAL_MARGIN = 42


def find_source() -> Path:
    preferred = [
        ASSETS_DIR / "AL51i.jpg",
        ASSETS_DIR / "Leonex-logo-original.png",
        ASSETS_DIR / "2026-05-04 21_30_13-Window.png",
    ]
    for path in preferred:
        if path.exists():
            return path

    candidates = [
        path
        for path in ASSETS_DIR.glob("*.png")
        if path.name not in EXCLUDE and path.is_file()
    ]
    if not candidates:
        raise FileNotFoundError("No encuentro ningun PNG original en assets.")
    return max(candidates, key=lambda path: path.stat().st_mtime)


def dark_bbox(image: Image.Image) -> tuple[int, int, int, int]:
    rgba = image.convert("RGBA")
    pixels = rgba.load()
    xs: list[int] = []
    ys: list[int] = []
    for y in range(rgba.height):
      for x in range(rgba.width):
          r, g, b, a = pixels[x, y]
          if a == 0:
              continue
          brightness = (r + g + b) / 3
          if brightness < 105:
              xs.append(x)
              ys.append(y)

    if not xs or not ys:
        return (0, 0, image.width, image.height)

    pad = 8
    left = max(min(xs) - pad, 0)
    top = max(min(ys) - pad, 0)
    right = min(max(xs) + pad + 1, image.width)
    bottom = min(max(ys) + pad + 1, image.height)
    return (left, top, right, bottom)


def build_logo(source_path: Path) -> Image.Image:
    if source_path.suffix.lower() in {".jpg", ".jpeg"}:
        return build_full_color_logo(source_path)

    source = Image.open(source_path).convert("RGBA")
    crop = source.crop(dark_bbox(source))
    crop.thumbnail((LOGO_SIZE, LOGO_SIZE), Image.Resampling.LANCZOS)

    placed = Image.new("RGBA", (CANVAS_SIZE, CANVAS_SIZE), (255, 255, 255, 0))
    offset = ((CANVAS_SIZE - crop.width) // 2, (CANVAS_SIZE - crop.height) // 2)
    placed.alpha_composite(crop, offset)

    output = Image.new("RGBA", placed.size, (255, 255, 255, 0))
    src = placed.load()
    dst = output.load()
    cx = CANVAS_SIZE / 2
    cy = CANVAS_SIZE / 2
    radius = min(crop.width, crop.height) / 2

    for y in range(CANVAS_SIZE):
        for x in range(CANVAS_SIZE):
            r, g, b, a = src[x, y]
            if a == 0:
                continue

            dist = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5
            if dist > radius + 4:
                continue

            brightness = (r + g + b) / 3
            edge_alpha = 1.0
            if dist > radius - 3:
                edge_alpha = max(0.0, min(1.0, (radius + 4 - dist) / 7))

            # Fondo de tablero fuera del medallon: fuera. Blancos internos: dentro.
            if brightness > 220:
                dst[x, y] = (*WHITE, int(a * edge_alpha))
                continue

            if brightness < 170:
                strength = max(0.38, min(1.0, 1 - brightness / 180))
                dst[x, y] = (*AQUA, int(a * strength * edge_alpha))
            else:
                dst[x, y] = (*WHITE, int(a * edge_alpha))

    return fit_to_square(output.filter(ImageFilter.UnsharpMask(radius=1.1, percent=130, threshold=2)))


def build_full_color_logo(source_path: Path) -> Image.Image:
    source = Image.open(source_path).convert("RGB")
    pixels = source.load()
    xs: list[int] = []
    ys: list[int] = []

    for y in range(source.height):
        for x in range(source.width):
            r, g, b = pixels[x, y]
            if g > 105 and b > 95 and g > r * 1.35:
                xs.append(x)
                ys.append(y)

    if xs and ys:
        pad = 42
        left = max(min(xs) - pad, 0)
        top = max(min(ys) - pad, 0)
        right = min(max(xs) + pad + 1, source.width)
        bottom = min(max(ys) + pad + 1, source.height)
        crop = source.crop((left, top, right, bottom))
    else:
        crop = source

    side = max(crop.width, crop.height)
    square = Image.new("RGB", (side, side), (6, 12, 13))
    offset = ((side - crop.width) // 2, (side - crop.height) // 2)
    square.paste(crop, offset)
    square = square.resize((CANVAS_SIZE, CANVAS_SIZE), Image.Resampling.LANCZOS)

    square = ImageEnhance.Contrast(square).enhance(1.12)
    square = ImageEnhance.Sharpness(square).enhance(1.28)
    square = ImageEnhance.Color(square).enhance(1.08)
    return square.convert("RGBA")


def fit_to_square(image: Image.Image) -> Image.Image:
    bbox = image.getbbox()
    if bbox is None:
        return image

    cropped = image.crop(bbox)
    target = CANVAS_SIZE - FINAL_MARGIN * 2
    scale = target / max(cropped.width, cropped.height)
    resized_size = (
        max(1, round(cropped.width * scale)),
        max(1, round(cropped.height * scale)),
    )
    cropped = cropped.resize(resized_size, Image.Resampling.LANCZOS)

    final = Image.new("RGBA", (CANVAS_SIZE, CANVAS_SIZE), (255, 255, 255, 0))
    offset = ((CANVAS_SIZE - cropped.width) // 2, (CANVAS_SIZE - cropped.height) // 2)
    final.alpha_composite(cropped, offset)
    return final


def main() -> None:
    source = find_source()
    logo = build_logo(source)
    logo.save(OUTPUT_PATH)
    print(f"Fuente: {source}")
    print(f"Logo final: {OUTPUT_PATH}")


if __name__ == "__main__":
    main()

