"""Theme picker modal screen for Navi Code TUI."""

from __future__ import annotations

from textual import events
from textual.app import ComposeResult
from textual.containers import Container
from textual.screen import ModalScreen
from textual.widgets import Input, Label, ListItem, ListView, Static

from clients.terminal.tui.themes import ThemeRegistry, set_active_theme


class ThemePickerScreen(ModalScreen[str | None]):
    """A palette-like screen for switching themes with live preview.

    Dismisses with the selected theme name or None if cancelled.
    """

    NAME = "ThemePickerScreen"

    DEFAULT_CSS = """
    ThemePickerScreen {
        align: center middle;
    }
    ThemePickerScreen > Container {
        width: 60;
        height: auto;
        max-height: 24;
        border: thick $tui-primary;
        background: $tui-surface;
        padding: 0 0 1 0;
    }
    ThemePickerScreen .title {
        text-style: bold;
        color: $tui-primary;
        background: $tui-panel;
        padding: 1;
        height: auto;
        text-align: center;
    }
    ThemePickerScreen Input {
        height: auto;
        border: none;
        border-bottom: solid $tui-border;
        background: $tui-background;
        color: $tui-text;
        padding: 0 1;
        margin: 0;
    }
    ThemePickerScreen ListView {
        height: auto;
        max-height: 16;
        border: none;
        background: $tui-surface;
        padding: 0;
        margin: 0;
    }
    ThemePickerScreen ListItem {
        color: $tui-text;
        background: transparent;
        height: auto;
        padding: 0 1;
    }
    ThemePickerScreen ListItem.--highlight {
        background: $tui-selection;
        color: $tui-background;
    }
    ThemePickerScreen .empty {
        color: $tui-text-dim;
        text-align: center;
        padding: 1;
    }
    """

    BINDINGS = [
        ("escape", "dismiss_cancel", "Cancel"),
    ]

    def __init__(self, current_theme: str) -> None:
        super().__init__()
        self._current_theme = current_theme
        self._original_theme = current_theme
        self._themes = ThemeRegistry.all()
        self._filtered = list(self._themes)
        self._list_items: list[ListItem] = []
        # Debounced live preview: apply_theme re-renders every chat bubble, so
        # applying it on every highlight while scrolling the theme list would
        # stutter. Coalesce rapid highlight moves into one apply per ~100 ms.
        self._preview_timer = None
        self._pending_preview: str | None = None

    def compose(self) -> ComposeResult:
        with Container():
            yield Static("Pick a theme (live preview)", classes="title")
            yield Input(placeholder="Type to filter themes...", id="theme-input")
            yield ListView(id="theme-list")

    def on_mount(self) -> None:
        self._render_list()
        list_view = self.query_one("#theme-list", ListView)
        list_view.focus()

    def _render_list(self) -> None:
        list_view = self.query_one("#theme-list", ListView)
        list_view.clear()
        self._list_items = []
        if not self._filtered:
            list_view.append(ListItem(Static("No matching themes", classes="empty")))
            return
        selected_index = 0
        for index, name in enumerate(self._filtered):
            label = Label(name)
            if name == self._current_theme:
                label.update(f"[b]* {name}[/b]")
                selected_index = index
            self._list_items.append(ListItem(label))
            list_view.append(self._list_items[-1])
        list_view.index = selected_index

    def _preview_theme(self, name: str) -> None:
        self._current_theme = name
        app = self.app
        app.theme = name
        set_active_theme(name)
        app.apply_theme()
        self._render_list()

    def _schedule_preview(self, name: str) -> None:
        """Remember the latest highlighted theme and apply it once per ~100 ms.

        Re-scheduling the timer is deliberately avoided: a rapid burst of
        highlights coalesces — the single pending fire picks up the freshest
        ``_pending_preview``. """
        self._pending_preview = name
        if self._preview_timer is None:
            self._preview_timer = self.set_timer(0.1, self._apply_pending_preview)

    def _apply_pending_preview(self) -> None:
        self._preview_timer = None
        name = self._pending_preview
        self._pending_preview = None
        if name is not None:
            self._preview_theme(name)

    def _cancel_pending_preview(self) -> None:
        if self._preview_timer is not None:
            self._preview_timer.stop()
            self._preview_timer = None
        self._pending_preview = None

    def _restore_original(self) -> None:
        # Cancel any pending preview first, otherwise it would fire after the
        # restore and re-apply the highlighted (not original) theme.
        self._cancel_pending_preview()
        app = self.app
        app.theme = self._original_theme
        set_active_theme(self._original_theme)
        app.apply_theme()

    def _filter(self, query: str) -> None:
        query = query.strip().lower()
        if not query:
            self._filtered = list(self._themes)
        else:
            self._filtered = [name for name in self._themes if query in name.lower()]
        self._render_list()

    def _select_highlighted(self) -> None:
        # The caller (ThemesCommand callback) applies the chosen theme itself;
        # cancel a pending preview so it cannot fire after dismiss and override
        # the selection (or restore) with whatever was highlighted mid-scroll.
        self._cancel_pending_preview()
        list_view = self.query_one("#theme-list", ListView)
        highlighted = list_view.index
        if highlighted is not None and 0 <= highlighted < len(self._filtered):
            self.dismiss(self._filtered[highlighted])
        elif self._filtered:
            self.dismiss(self._filtered[0])

    def on_input_changed(self, event: Input.Changed) -> None:
        self._filter(event.value)

    def on_input_submitted(self, event: Input.Submitted) -> None:
        self._select_highlighted()

    def on_list_view_selected(self, event: ListView.Selected) -> None:
        index = self._list_items.index(event.item) if event.item in self._list_items else None
        if index is not None:
            self.dismiss(self._filtered[index])

    def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
        index = self._list_items.index(event.item) if event.item in self._list_items else None
        if index is not None:
            self._schedule_preview(self._filtered[index])

    def on_key(self, event: events.Key) -> None:
        list_view = self.query_one("#theme-list", ListView)
        if event.key == "down":
            list_view.action_cursor_down()
            event.stop()
            event.prevent_default()
        elif event.key == "up":
            list_view.action_cursor_up()
            event.stop()
            event.prevent_default()
        elif event.key in ("enter", "return"):
            self._select_highlighted()
            event.stop()
            event.prevent_default()
        elif event.key == "escape":
            self._restore_original()
            self.dismiss(None)
            event.stop()
            event.prevent_default()

    def action_dismiss_cancel(self) -> None:
        self._restore_original()
        self.dismiss(None)
