"""Genera un icono .ico multi-resolucion para apps C++ del registry.

Rasteriza un icono Phosphor SVG sobre un fondo redondeado del color accent
y exporta un .ico con multiples resoluciones (16, 24, 32, 48, 64, 128, 256).

Funciones publicas reutilizables:
    _find_registry_root  — localiza la raiz del registry
    _render_glyph_white  — rasteriza un SVG Phosphor como glyph blanco RGBA
    _make_icon_image     — compone fondo redondeado + glyph en un PIL.Image
"""
import io
import os
from pathlib import Path

import cairosvg
from PIL import Image, ImageDraw


DEFAULT_SIZES = [16, 24, 32, 48, 64, 128, 256]


def _find_registry_root(registry_root: str | None = None) -> Path:
    """Descubre la raiz del registry.

    Prioridad: argumento explicito > FN_REGISTRY_ROOT env > caminar hacia arriba
    desde el archivo hasta encontrar registry.db.

    Args:
        registry_root: Ruta absoluta opcional. Si se pasa, se devuelve directamente.

    Returns:
        Path resuelto a la raiz del registry.

    Raises:
        FileNotFoundError: Si no se puede localizar registry.db.
    """
    if registry_root is not None:
        return Path(registry_root).resolve()
    env_root = os.environ.get("FN_REGISTRY_ROOT")
    if env_root:
        return Path(env_root).resolve()
    current = Path(__file__).resolve()
    for parent in current.parents:
        if (parent / "registry.db").exists():
            return parent
    raise FileNotFoundError(
        "No se encontro registry.db caminando desde el archivo hasta la raiz. "
        "Define FN_REGISTRY_ROOT en el entorno."
    )


def _hex_to_rgb(h: str) -> tuple[int, int, int]:
    h = h.lstrip("#")
    return tuple(int(h[i: i + 2], 16) for i in (0, 2, 4))


def _render_glyph_white(svg_path: Path, size: int) -> Image.Image:
    """Renderiza el SVG Phosphor como glyph blanco sobre fondo transparente.

    Args:
        svg_path: Ruta al archivo .svg de Phosphor.
        size: Ancho/alto en pixels del output.

    Returns:
        Imagen RGBA con el glyph en blanco sobre fondo transparente.
    """
    svg = svg_path.read_text(encoding="utf-8")
    # Phosphor usa fill="currentColor" — forzar blanco.
    svg = svg.replace('fill="currentColor"', 'fill="#ffffff"')
    png_bytes = cairosvg.svg2png(
        bytestring=svg.encode("utf-8"),
        output_width=size,
        output_height=size,
    )
    return Image.open(io.BytesIO(png_bytes)).convert("RGBA")


def _make_icon_image(svg_path: Path, accent_hex: str, size: int) -> Image.Image:
    """Compone fondo redondeado con color accent + glyph blanco centrado al 70%.

    Args:
        svg_path: Ruta al archivo .svg de Phosphor.
        accent_hex: Color de fondo en formato "#RRGGBB".
        size: Ancho/alto en pixels del canvas de salida.

    Returns:
        Imagen RGBA lista para guardar como PNG o ICO.
    """
    bg_color = _hex_to_rgb(accent_hex) + (255,)
    canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(canvas)
    radius = max(2, size // 6)  # ~16% de radio redondeado
    draw.rounded_rectangle(
        [(0, 0), (size - 1, size - 1)],
        radius=radius,
        fill=bg_color,
    )
    # El glyph ocupa ~70% del canvas (padding ~15% en cada lado).
    glyph_size = int(size * 0.7)
    if glyph_size < 8:
        glyph_size = max(8, size - 2)
    glyph = _render_glyph_white(svg_path, glyph_size)
    off = ((size - glyph_size) // 2, (size - glyph_size) // 2)
    canvas.alpha_composite(glyph, dest=off)
    return canvas


def generate_app_icon(
    phosphor_icon_name: str,
    accent_hex: str,
    out_ico_path: str,
    *,
    weight: str = "fill",
    sizes: list[int] = None,
    phosphor_root: str = None,
) -> str:
    """Genera un icono .ico multi-resolucion a partir de un SVG Phosphor.

    Rasteriza el icono Phosphor indicado sobre un fondo redondeado del color
    accent y exporta un .ico con multiples resoluciones ordenadas de mayor a
    menor para maxima compatibilidad con Windows.

    Args:
        phosphor_icon_name: Nombre del icono Phosphor sin sufijo de weight
            (ej. "chart-bar", "tree-structure", "gauge").
        accent_hex: Color de fondo en formato hexadecimal "#RRGGBB"
            (ej. "#0ea5e9", "#7c3aed").
        out_ico_path: Ruta de salida para el archivo .ico. Puede ser absoluta
            o relativa al directorio de trabajo actual. El directorio padre
            se crea si no existe.
        weight: Variante del icono Phosphor. Default "fill". Otros valores
            validos segun el repositorio: "regular", "bold", "light",
            "thin", "duotone".
        sizes: Lista de resoluciones a incluir en el .ico. Default
            [16, 24, 32, 48, 64, 128, 256]. El orden no importa; se
            renderiza cada tamano individualmente para maxima crispness.
        phosphor_root: Ruta a la carpeta raiz de assets de phosphor-core
            (la que contiene subdirectorios "fill", "regular", etc.).
            Default: <registry_root>/sources/phosphor-core/assets.

    Returns:
        Ruta absoluta del archivo .ico generado.

    Raises:
        FileNotFoundError: Si el SVG del icono no existe en phosphor_root.
        ValueError: Si accent_hex no tiene el formato "#RRGGBB".
    """
    if sizes is None:
        sizes = DEFAULT_SIZES

    # Resolver raiz de phosphor
    if phosphor_root is None:
        _root = _find_registry_root()
        phosphor_assets = _root / "sources" / "phosphor-core" / "assets"
    else:
        phosphor_assets = Path(phosphor_root)

    svg_file = phosphor_assets / weight / f"{phosphor_icon_name}-{weight}.svg"
    if not svg_file.exists():
        raise FileNotFoundError(
            f"Icono Phosphor no encontrado: {svg_file}\n"
            f"Asegurate de que sources/phosphor-core/ existe. Si no:\n"
            f"  git clone --depth=1 https://github.com/phosphor-icons/core.git "
            f"sources/phosphor-core"
        )

    # Validar formato del color
    h = accent_hex.lstrip("#")
    if len(h) != 6:
        raise ValueError(f"accent_hex debe tener formato #RRGGBB, recibido: {accent_hex!r}")

    # Renderizar cada resolucion individualmente para crispness en tamanos pequeños
    images = {s: _make_icon_image(svg_file, accent_hex, s) for s in sorted(sizes, reverse=True)}

    out = Path(out_ico_path)
    if not out.is_absolute():
        out = Path.cwd() / out
    out.parent.mkdir(parents=True, exist_ok=True)

    sorted_sizes = sorted(sizes, reverse=True)
    biggest = images[sorted_sizes[0]]
    others = [images[s] for s in sorted_sizes[1:]]
    biggest.save(
        out,
        format="ICO",
        sizes=[(s, s) for s in sorted_sizes],
        append_images=others,
    )

    return str(out.resolve())
