"""Palette picker with Color Brewer swatches, grouped by type."""
from pathlib import Path

from nicegui import ui

from .local_file_picker import LocalFilePicker


# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------

# Color Brewer palettes by category
SEQUENTIAL = [
    "Blues", "Greens", "Greys", "Oranges", "Purples",
    "BuGn", "BuPu", "GnBu", "OrRd", "PuBu", "PuBuGn", "PuRd", "RdPu",
    "YlGn", "YlGnBu", "YlOrBr", "YlOrRd",
]
DIVERGING = [
    "BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdGy", "RdYlBu", "RdYlGn", "Spectral",
]
QUALITATIVE = [
    "Accent", "Dark2", "Paired", "Pastel1", "Pastel2", "Set1", "Set2", "Set3",
]
EXTRA = ["tab10", "tab20"]

# Flat dict value->label for NiceGUI select (value must be in options keys)
ALL_PALETTES = (
    [(p, f"Sequential: {p}") for p in SEQUENTIAL]
    + [(p, f"Diverging: {p}") for p in DIVERGING]
    + [(p, f"Qualitative: {p}") for p in QUALITATIVE]
    + [(p, p) for p in EXTRA]
)
FLAT_OPTIONS = {v: l for v, l in ALL_PALETTES}


# -----------------------------------------------------------------------------
# Public API
# -----------------------------------------------------------------------------

def palette_picker(
    value: str = "",
    on_change=None,
    label: str = "Palette",
    show_custom: bool = True,
    state: dict | None = None,
) -> ui.select:
    """Render a palette dropdown with color swatches.
    When show_custom=True and state is provided, adds Custom option with file picker.
    """
    if state is not None and state.get("custom_palette") and not state.get("palette"):
        state["palette"] = "__custom__"
    options = dict(FLAT_OPTIONS)
    if show_custom and state is not None:
        options = {"__custom__": "Custom (file)", **options}

    def _on_palette_change():
        v = select.value
        if v == "__custom__":
            swatch_container.clear()
            with swatch_container:
                ui.label("Select custom palette file below").classes("text-sm text-gray-500")
            custom_row.set_visibility(True)
        elif v:
            custom_row.set_visibility(False)
            hex_colors = _palette_to_hex(v)
            swatch_container.clear()
            with swatch_container:
                for h in hex_colors:
                    ui.element("span").style(
                        f"display:inline-block;width:14px;height:14px;background:{h};margin:0 1px;border-radius:2px;"
                    )
        if on_change:
            on_change()

    # Initial value: use custom if custom_palette is set
    init_val = value or (state.get("palette") if state else None)
    if not init_val and state and state.get("custom_palette"):
        init_val = "__custom__"
    elif not init_val:
        init_val = "Blues"  # default when empty (must be in options)
    select = ui.select(
        options=options,
        value=init_val,
        label=label,
        on_change=_on_palette_change,
    ).classes("w-full")
    if state is not None:
        select.bind_value(state, "palette")

    swatch_container = ui.row().classes("gap-1 mt-1 flex-wrap")
    custom_row = ui.row().classes("w-full mt-2")

    async def _open_picker():
        picker = LocalFilePicker(str(Path.home()), multiple=False)
        result = await picker
        if result and result[0]:
            custom_input.value = result[0]
            if state is not None:
                state["custom_palette"] = result[0]

    with custom_row:
        custom_input = ui.input("Custom palette path", value=state.get("custom_palette", "") if state else "", placeholder="e.g.: /path/to/palette.txt").classes("flex-1")
        if state is not None:
            custom_input.bind_value(state, "custom_palette")
        ui.button(icon="folder_open", on_click=_open_picker).props("flat round dense")

    # Show custom row if custom_palette is set or Custom is selected
    use_custom = init_val == "__custom__" or (state and state.get("custom_palette"))
    custom_row.set_visibility(use_custom)

    if init_val:
        _on_palette_change()

    return select


# -----------------------------------------------------------------------------
# Helpers
# -----------------------------------------------------------------------------

def _palette_to_hex(palette_name: str, n: int = 5) -> list[str]:
    """Get hex colors for a palette (for swatch display)."""
    try:
        import seaborn as sns

        pal = sns.color_palette(palette_name, n_colors=n)
        if hasattr(pal, "as_hex"):
            return list(pal.as_hex())
        import matplotlib.colors as mcolors

        return [mcolors.rgb2hex(c) for c in pal]
    except Exception:
        return ["#808080"] * n
