"""Theme selection system for AiCippy CLI.

Provides beautiful color themes with rich selection UI:
- Neon Night (default): Vibrant purple/blue neon palette
- Ocean Blue: Cool ocean-inspired blues and teals
- Forest Green: Natural greens and earthy tones
- Sunset: Warm oranges and golden hues
- Minimal: Clean grayscale with subtle accents
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Final

from rich.box import ROUNDED
from rich.panel import Panel
from rich.text import Text

from aicippy.utils.logging import get_logger

if TYPE_CHECKING:
    from rich.console import Console

logger = get_logger(__name__)


# ============================================================================
# Theme Dataclass
# ============================================================================


@dataclass(frozen=True)
class Theme:
    """A complete color theme for the CLI interface."""

    name: str
    primary: str
    secondary: str
    accent: str
    success: str
    warning: str
    error: str
    info: str
    border_style: str
    text_style: str
    bg_panel: str
    description: str


# ============================================================================
# Theme Definitions
# ============================================================================

THEMES: Final[dict[str, Theme]] = {
    "Neon Night": Theme(
        name="Neon Night",
        primary="#667eea",
        secondary="#764ba2",
        accent="#a78bfa",
        success="#10b981",
        warning="#f59e0b",
        error="#ef4444",
        info="#3b82f6",
        border_style="#667eea",
        text_style="white",
        bg_panel="dim",
        description="Vibrant neon purples and electric blues",
    ),
    "Ocean Blue": Theme(
        name="Ocean Blue",
        primary="#0ea5e9",
        secondary="#0284c7",
        accent="#06b6d4",
        success="#22c55e",
        warning="#eab308",
        error="#f43f5e",
        info="#38bdf8",
        border_style="#0ea5e9",
        text_style="white",
        bg_panel="dim blue",
        description="Cool ocean waves and deep sea tones",
    ),
    "Forest Green": Theme(
        name="Forest Green",
        primary="#22c55e",
        secondary="#15803d",
        accent="#a3e635",
        success="#4ade80",
        warning="#fbbf24",
        error="#f87171",
        info="#34d399",
        border_style="#22c55e",
        text_style="white",
        bg_panel="dim green",
        description="Natural forest greens and earthy hues",
    ),
    "Sunset": Theme(
        name="Sunset",
        primary="#f97316",
        secondary="#ea580c",
        accent="#fb923c",
        success="#84cc16",
        warning="#facc15",
        error="#ef4444",
        info="#f59e0b",
        border_style="#f97316",
        text_style="white",
        bg_panel="dim",
        description="Warm sunset oranges and golden light",
    ),
    "Minimal": Theme(
        name="Minimal",
        primary="#6b7280",
        secondary="#4b5563",
        accent="#9ca3af",
        success="#22c55e",
        warning="#f59e0b",
        error="#ef4444",
        info="#60a5fa",
        border_style="#6b7280",
        text_style="#e5e7eb",
        bg_panel="dim",
        description="Clean and understated monochrome",
    ),
}

DEFAULT_THEME_NAME: Final[str] = "Neon Night"

# ============================================================================
# Active Theme State — single source of truth for brand colors
# ============================================================================

# Module-level mutable state: updated by set_active_theme()
_active_theme: Theme = THEMES["Neon Night"]

# Brand color accessors (always reflect the active theme)
BRAND_PRIMARY: str = _active_theme.primary
BRAND_SECONDARY: str = _active_theme.secondary
BRAND_ACCENT: str = _active_theme.accent
BRAND_SUCCESS: str = _active_theme.success
BRAND_WARNING: str = _active_theme.warning
BRAND_ERROR: str = _active_theme.error
BRAND_INFO: str = _active_theme.info


def set_active_theme(name: str) -> Theme:
    """Set the active theme and update all BRAND_* module variables.

    Args:
        name: Theme name (falls back to default if not found).

    Returns:
        The newly active Theme.

    """
    global _active_theme  # noqa: PLW0603
    global BRAND_PRIMARY, BRAND_SECONDARY, BRAND_ACCENT  # noqa: PLW0603
    global BRAND_SUCCESS, BRAND_WARNING, BRAND_ERROR, BRAND_INFO  # noqa: PLW0603

    _active_theme = THEMES.get(name, THEMES[DEFAULT_THEME_NAME])
    BRAND_PRIMARY = _active_theme.primary
    BRAND_SECONDARY = _active_theme.secondary
    BRAND_ACCENT = _active_theme.accent
    BRAND_SUCCESS = _active_theme.success
    BRAND_WARNING = _active_theme.warning
    BRAND_ERROR = _active_theme.error
    BRAND_INFO = _active_theme.info
    return _active_theme


def get_active_theme() -> Theme:
    """Return the currently active theme."""
    return _active_theme


# ============================================================================
# Theme Access Functions
# ============================================================================


def get_available_themes() -> list[str]:
    """Return a list of all available theme names."""
    return list(THEMES.keys())


def get_theme(name: str) -> Theme:
    """Return a Theme dataclass by name.

    Falls back to the default theme if the name is not found.

    Args:
        name: Theme name (case-sensitive match against THEMES dict).

    Returns:
        The matching Theme dataclass.

    """
    return THEMES.get(name, THEMES[DEFAULT_THEME_NAME])


# ============================================================================
# Theme Preview Swatch
# ============================================================================


def _render_color_swatch(theme: Theme, selected: bool = False) -> Panel:
    """Render a compact color swatch panel for a single theme.

    Args:
        theme: The theme to render.
        selected: Whether this theme is currently selected.

    Returns:
        A Rich Panel showing the theme colors.

    """
    content = Text()

    # Color bar - a row of colored blocks showing the palette
    colors = [
        ("PRI", theme.primary),
        ("ACC", theme.accent),
        ("SUC", theme.success),
        ("WRN", theme.warning),
        ("ERR", theme.error),
        ("INF", theme.info),
    ]
    for _label, color in colors:
        content.append(" \u2588\u2588 ", style=f"bold {color}")
    content.append("\n")

    # Label row underneath
    for label, color in colors:
        content.append(f" {label} ", style=f"dim {color}")
    content.append("\n\n")

    # Description
    content.append(f"  {theme.description}", style="dim italic")

    border = f"bold {theme.primary}" if selected else theme.border_style
    title_prefix = "\u2713 " if selected else "  "
    title_style = f"bold {theme.primary}" if selected else f"{theme.primary}"

    return Panel(
        content,
        title=f"[{title_style}]{title_prefix}{theme.name}[/{title_style}]",
        title_align="left",
        border_style=border,
        box=ROUNDED,
        padding=(0, 1),
    )


# ============================================================================
# Theme Selection UI
# ============================================================================


def prompt_theme_selection(console: Console, current_theme: str = DEFAULT_THEME_NAME) -> str:
    """Display a beautiful theme selection panel and prompt the user to choose.

    Shows all available themes with color previews and returns the selected
    theme name. If the user presses Enter without choosing, the current_theme
    is returned as default.

    Args:
        console: Rich Console instance for rendering.
        current_theme: Name of the currently active theme (highlighted).

    Returns:
        The name of the selected theme.

    """
    # Header
    header = Text()
    header.append("\n")
    header.append("  \u2728 ", style="bold")
    header.append("Theme Selection", style="bold #a78bfa")
    header.append("  \u2500  ", style="dim")
    header.append("Choose a color theme for your session", style="dim italic")
    header.append("\n")
    console.print(header)

    theme_names = get_available_themes()

    # Display all theme swatches
    for idx, name in enumerate(theme_names, start=1):
        theme = THEMES[name]
        is_selected = name == current_theme
        swatch = _render_color_swatch(theme, selected=is_selected)

        # Add number prefix for selection
        number_text = Text()
        number_text.append(f"  [{idx}] ", style=f"bold {theme.primary}")
        console.print(number_text, end="")
        console.print(swatch)

    # Selection prompt
    prompt_text = Text()
    prompt_text.append("\n")
    prompt_text.append("  \u276f Select theme ", style="bold #a78bfa")
    prompt_text.append(f"[1-{len(theme_names)}]", style="bold white")
    prompt_text.append(f" (Enter for '{current_theme}'): ", style="dim")
    console.print(prompt_text, end="")

    try:
        choice = input().strip()
    except (EOFError, KeyboardInterrupt):
        console.print()
        return current_theme

    # Parse selection
    if not choice:
        return current_theme

    # Try numeric selection
    try:
        idx = int(choice)
        if 1 <= idx <= len(theme_names):
            selected = theme_names[idx - 1]
            selected_theme = THEMES[selected]
            console.print(
                Panel(
                    Text(
                        f"  \u2713 Theme set to: {selected}",
                        style=f"bold {selected_theme.primary}",
                    ),
                    border_style=selected_theme.primary,
                    box=ROUNDED,
                    padding=(0, 1),
                ),
            )
            return selected
    except ValueError:
        logger.debug("theme_numeric_selection_parse_failed", exc_info=True)

    # Try name match (case-insensitive partial)
    choice_lower = choice.lower()
    for name in theme_names:
        if choice_lower in name.lower():
            matched_theme = THEMES[name]
            console.print(
                Panel(
                    Text(
                        f"  \u2713 Theme set to: {name}",
                        style=f"bold {matched_theme.primary}",
                    ),
                    border_style=matched_theme.primary,
                    box=ROUNDED,
                    padding=(0, 1),
                ),
            )
            return name

    # Invalid choice - keep current
    console.print(Text(f"  Invalid selection. Keeping '{current_theme}'.", style="dim italic"))
    return current_theme
