"""
命令列表组件
- CommandList: 支持搜索过滤、二级菜单、滚动
"""

from textual.widgets import Static
from textual.containers import VerticalScroll
from rich.text import Text

from integrations.cli.styles import Styles


# 需要二级菜单的命令 → 子菜单数据 key
COMMAND_SUB_MENUS = {
    "model": "models",
    "mode": "agents",
    "session": "sessions",
    "auto": "auto_options",
}

# auto 命令的子菜单选项
AUTO_OPTIONS = [
    ("on", "开启自动模式（跳过所有权限确认）"),
    ("off", "关闭自动模式（恢复权限确认）"),
]

# 无参数命令，选中后直接提交
DIRECT_EXECUTE_COMMANDS = {
    "exit", "quit", "clear", "cls", "compact",
    "help", "status", "tools", "todo", "todos",
    "debug", "config", "skills", "init",
}


class CommandList(VerticalScroll):
    """命令列表显示组件 - 支持搜索过滤、二级菜单、滚动"""

    DEFAULT_CSS = """
    CommandList {
        height: auto;
        min-height: 1;
        max-height: 20;
        padding: 0 1 1 1;
    }
    CommandList > .command-list-content {
        height: auto;
    }
    """

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._content = Static(Text(""), classes="command-list-content")
        self._commands: list = []       # [(name, desc, category), ...]
        self._filtered: list = []       # 过滤后的索引列表
        self._selected_index: int = 0
        self._sub_menu: str = ""
        self._sub_options: list = []
        self._extra_data: dict = {}

    def compose(self):
        yield self._content

    def set_extra_data(self, data: dict):
        """设置额外数据（models, agents 等）"""
        self._extra_data = data

    def set_commands(self, commands: list, search: str = ""):
        """设置命令列表并按搜索词过滤"""
        self._commands = commands
        self._sub_menu = ""
        self._sub_options = []
        self.filter(search)

    def filter(self, search: str = ""):
        """按搜索词过滤命令列表"""
        search = search.lower().strip()
        if search:
            self._filtered = [
                i for i, (name, _, _) in enumerate(self._commands)
                if search in name.lower()
            ]
        else:
            self._filtered = list(range(len(self._commands)))
        self._selected_index = 0

        if not self._filtered:
            self._content.update(Text(""))
            self.display = False
        else:
            self.display = True
            self._refresh_display()

    def set_sub_menu(self, sub_menu: str, options: list):
        """切换到二级子菜单"""
        self._sub_menu = sub_menu
        self._sub_options = options
        self._selected_index = 0
        self._refresh_display()

    def back_to_main(self):
        """返回主菜单"""
        self._sub_menu = ""
        self._sub_options = []
        self._selected_index = 0
        self._refresh_display()

    def select_next(self):
        """选择下一个"""
        items = self._sub_options if self._sub_menu else self._filtered
        if items:
            self._selected_index = (self._selected_index + 1) % len(items)
            self._refresh_display()

    def select_prev(self):
        """选择上一个"""
        items = self._sub_options if self._sub_menu else self._filtered
        if items:
            self._selected_index = (self._selected_index - 1) % len(items)
            self._refresh_display()

    def get_selected(self):
        """获取当前选中项：主菜单返回 (name, desc, cat)，子菜单返回 str(值)"""
        if self._sub_menu and self._sub_options:
            if 0 <= self._selected_index < len(self._sub_options):
                item = self._sub_options[self._selected_index]
                return item[0] if isinstance(item, tuple) else item
        elif self._filtered:
            if 0 <= self._selected_index < len(self._filtered):
                return self._commands[self._filtered[self._selected_index]]
        return None

    def is_sub_menu(self) -> bool:
        return bool(self._sub_menu)

    def _scroll_to_selected(self, total: int):
        """滚动到选中项可见"""
        if total <= 0:
            return
        self.scroll_to(y=max(0, self._selected_index - 5), animate=False)

    def _refresh_display(self):
        """渲染命令列表"""
        if self._sub_menu and self._sub_options:
            self._render_sub_menu()
            return

        if not self._filtered:
            self._content.update(Text("  无匹配命令", style="dim"))
            return

        lines = Text()
        for sel_i, cmd_i in enumerate(self._filtered):
            name, desc, _ = self._commands[cmd_i]
            if sel_i > 0:
                lines.append("\n")
            if sel_i == self._selected_index:
                lines.append(" ▸ ", style=Styles.CMD_LIST_ARROW)
                lines.append(f"/{name}  ", style="bold")
                lines.append(desc, style="bold dim")
            else:
                lines.append(f"   /{name}  ")
                lines.append(desc, style="dim")
        self._content.update(lines)
        self._scroll_to_selected(len(self._filtered))

    def _render_sub_menu(self):
        """渲染二级子菜单，支持 str 和 (value, desc) 格式"""
        if self._sub_menu not in ("session_cmds",):
            if self._sub_menu in self._extra_data:
                self._sub_options = self._extra_data[self._sub_menu]

        if not self._sub_options:
            self._content.update(Text("  无可用选项", style="dim"))
            return

        title_map = {
            "models": "模型",
            "agents": "Agent",
            "sessions": "会话",
            "session_cmds": "会话操作",
            "auto_options": "自动模式",
        }
        title = title_map.get(self._sub_menu, "选项")
        hide_value = self._sub_menu == "sessions"

        if self._sub_menu == "models":
            self._render_models_grouped()
            return

        lines = Text()
        lines.append(f" 选择 {title}:\n", style="dim")
        for i, option in enumerate(self._sub_options):
            if i > 0:
                lines.append("\n")
            if isinstance(option, tuple):
                value, desc = option[0], option[1]
            else:
                value, desc = option, ""
            display = desc if (hide_value and desc) else value
            if i == self._selected_index:
                lines.append(" ▸ ", style=Styles.CMD_LIST_ARROW)
                lines.append(display, style="bold")
                if not hide_value and desc:
                    lines.append(f"  {desc}", style="bold dim")
            else:
                lines.append(f"   {display}")
                if not hide_value and desc:
                    lines.append(f"  {desc}", style="dim")
        self._content.update(lines)
        self._scroll_to_selected(len(self._sub_options))

    def _render_models_grouped(self):
        """按 provider 分组渲染模型列表"""
        groups: list = []
        group_map: dict = {}
        for i, option in enumerate(self._sub_options):
            value = option[0] if isinstance(option, tuple) else option
            provider = value.split("/", 1)[0] if "/" in value else "other"
            if provider not in group_map:
                group_map[provider] = []
                groups.append((provider, group_map[provider]))
            group_map[provider].append(i)

        lines = Text()
        lines.append(" 选择模型:\n", style="dim")
        first_line = True
        for provider, indices in groups:
            if not first_line:
                lines.append("\n")
            first_line = False
            lines.append(f" [{provider}]\n", style="bold dim")
            for j, idx in enumerate(indices):
                option = self._sub_options[idx]
                value = option[0] if isinstance(option, tuple) else option
                if j > 0:
                    lines.append("\n")
                if idx == self._selected_index:
                    lines.append("   ▸ ", style=Styles.CMD_LIST_ARROW)
                    lines.append(value, style="bold")
                else:
                    lines.append(f"     {value}")
        self._content.update(lines)
        self._scroll_to_selected(len(self._sub_options))

    def clear(self):
        """清除命令列表"""
        self._commands = []
        self._filtered = []
        self._selected_index = 0
        self._sub_menu = ""
        self._sub_options = []
        self._content.update(Text(""))
        self.scroll_home(animate=False)
