"""BrowserView — drill topic/category browser with progress boxes."""

from __future__ import annotations

from dataclasses import dataclass

from textual.app import ComposeResult
from textual.containers import VerticalScroll
from textual.message import Message
from textual.widgets import OptionList, Static
from textual.widgets.option_list import Option


class BrowserView(VerticalScroll):
    """Drill browser showing quiz topics and coding categories with progress."""

    @dataclass
    class TopicSelected(Message):
        topic: str

    @dataclass
    class CategorySelected(Message):
        category: str

    def __init__(self, **kwargs) -> None:
        super().__init__(**kwargs)
        self.quiz_items: list[dict] = []
        self.category_items: list[dict] = []
        self._configured_topics: list[str] = []
        self._show_all_topics: bool = False
        self._show_all_categories: bool = False
        # Currently visible slices — kept in sync with rendered OptionList.
        self._visible_quiz: list[dict] = []
        self._visible_cats: list[dict] = []

    def compose(self) -> ComposeResult:
        yield Static("Quiz Topics", classes="browser-section-header")
        yield OptionList(id="quiz-topic-list")
        yield Static("", id="quiz-show-all")
        yield Static("Coding Problems", classes="browser-section-header")
        yield OptionList(id="coding-category-list")
        yield Static("", id="coding-show-all")
        yield Static(
            "[dim]\\[r] random quiz  \\[R] random code  \\[Enter] select  \\[a] show all[/dim]",
            id="browser-hint",
        )

    def load(
        self,
        topics: list[dict],
        categories: list[dict],
        configured_topics: list[str],
    ) -> None:
        """Populate the browser with data from API."""
        self._configured_topics = [t.lower() for t in configured_topics]
        # Sort: configured first, then alphabetical
        configured = [t for t in topics if t["topic"].lower() in self._configured_topics]
        unconfigured = [t for t in topics if t["topic"].lower() not in self._configured_topics]
        configured.sort(key=lambda t: t["topic"])
        unconfigured.sort(key=lambda t: t["topic"])
        self.quiz_items = configured + unconfigured
        self.category_items = sorted(categories, key=lambda c: c["category"])

        self._render_topic_list()
        self._render_category_list()

    def _render_topic_list(self) -> None:
        """Render quiz topic options."""
        topic_list = self.query_one("#quiz-topic-list", OptionList)
        topic_list.clear_options()

        items = self.quiz_items
        configured_count = sum(
            1 for t in items if t["topic"].lower() in self._configured_topics
        )

        # Show configured + in-progress, or all if expanded
        visible = items if self._show_all_topics else items[:max(configured_count, 4)]
        self._visible_quiz = list(visible)

        for t in visible:
            marker = " ★" if t["topic"].lower() in self._configured_topics else ""
            pct = (t["completed"] / t["total"] * 100) if t["total"] > 0 else 0
            acc = f"{t['accuracy']:.0%}" if t["completed"] > 0 else "—"
            label = f"{t['topic']}{marker}  {t['completed']}/{t['total']}  {pct:.0f}%  acc {acc}"
            topic_list.add_option(Option(label))

        show_all = self.query_one("#quiz-show-all", Static)
        hidden = len(items) - len(visible)
        if hidden > 0 and not self._show_all_topics:
            show_all.update(f"[dim]  ▸ Show all ({len(items)} topics)[/dim]")
        else:
            show_all.update("")

    def _render_category_list(self) -> None:
        """Render coding category options."""
        cat_list = self.query_one("#coding-category-list", OptionList)
        cat_list.clear_options()

        items = self.category_items
        visible = items if self._show_all_categories else items[:4]
        self._visible_cats = list(visible)

        for c in visible:
            pct = (c["solved"] / c["total"] * 100) if c["total"] > 0 else 0
            label = f"{c['category']}  {c['solved']}/{c['total']}  {pct:.0f}%"
            cat_list.add_option(Option(label))

        show_all = self.query_one("#coding-show-all", Static)
        hidden = len(items) - len(visible)
        if hidden > 0 and not self._show_all_categories:
            show_all.update(f"[dim]  ▸ Show all ({len(items)} categories)[/dim]")
        else:
            show_all.update("")

    def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
        """Handle selection in either topic or category list."""
        if event.option_list.id == "quiz-topic-list":
            idx = event.option_index
            if idx < len(self._visible_quiz):
                self.post_message(self.TopicSelected(self._visible_quiz[idx]["topic"]))
        elif event.option_list.id == "coding-category-list":
            idx = event.option_index
            if idx < len(self._visible_cats):
                self.post_message(self.CategorySelected(self._visible_cats[idx]["category"]))

    def toggle_show_all(self) -> None:
        """Toggle show-all for the currently focused section."""
        focused = self.app.focused
        if focused and getattr(focused, "id", "") == "quiz-topic-list":
            self._show_all_topics = not self._show_all_topics
            self._render_topic_list()
        elif focused and getattr(focused, "id", "") == "coding-category-list":
            self._show_all_categories = not self._show_all_categories
            self._render_category_list()
        else:
            # Default: toggle quiz topics when neither list is focused
            self._show_all_topics = not self._show_all_topics
            self._render_topic_list()

    def select_current(self) -> None:
        """Programmatically select the highlighted item in the focused list."""
        focused = self.app.focused
        if isinstance(focused, OptionList) and focused.highlighted is not None:
            focused.action_select()
