"""
Interactive Slash Command Menu

Provides an interactive menu when user types "/" in the REPL.
Displays all available slash commands with descriptions and allows
keyboard navigation and selection.

Example:
    menu = SlashCommandMenu(BUILT_IN_COMMANDS)
    selection = menu.show()
    if selection.selected:
        command_text = f"/{selection.command}"
"""

import sys
import termios
import tty
from dataclasses import dataclass
from typing import Optional

from rich.console import Console
from rich.panel import Panel
from rich.table import Table

from groknroll.tui.slash_commands import BUILT_IN_COMMANDS, CommandDefinition


@dataclass
class MenuSelection:
    """Result of menu interaction"""

    selected: bool  # True if user selected a command
    command: Optional[str] = None  # Selected command name (e.g., "help")
    cancelled: bool = False  # True if user pressed Esc


class SlashCommandMenu:
    """
    Interactive menu for slash commands.

    Features:
    - Keyboard navigation (↑/↓ arrows)
    - Selection with Enter
    - Cancel with Esc
    - Visual feedback with Rich

    Example:
        menu = SlashCommandMenu(BUILT_IN_COMMANDS)
        selection = menu.show()
        if selection.selected:
            return f"/{selection.command}"
    """

    def __init__(
        self,
        commands: list[CommandDefinition] | None = None,
        console: Console | None = None,
    ):
        """
        Initialize menu with available commands.

        Args:
            commands: List of command definitions (defaults to BUILT_IN_COMMANDS)
            console: Rich console for rendering
        """
        self.commands = commands if commands is not None else BUILT_IN_COMMANDS
        self.console = console or Console()
        self.selected_index: int = 0

    def show(self) -> MenuSelection:
        """
        Display interactive menu and wait for user selection.

        Returns:
            MenuSelection with user's choice

        Navigation:
            ↑/↓ - Navigate through commands
            Enter - Select highlighted command
            Esc - Cancel and close menu
        """
        # Reset selection
        self.selected_index = 0

        # Store original terminal settings
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)

        try:
            # Set terminal to raw mode for character-by-character input
            tty.setraw(fd)

            # Initial render
            self._render_menu()

            # Event loop
            while True:
                # Read single character
                char = sys.stdin.read(1)

                # Handle escape sequences (arrow keys)
                if char == '\x1b':  # ESC
                    # Check if it's an escape sequence or just ESC key
                    next_char = sys.stdin.read(1)
                    if next_char == '[':
                        # Arrow key sequence
                        arrow = sys.stdin.read(1)
                        if arrow == 'A':  # Up arrow
                            self._move_selection(-1)
                            self._render_menu()
                        elif arrow == 'B':  # Down arrow
                            self._move_selection(1)
                            self._render_menu()
                    else:
                        # Just ESC key - cancel
                        self._clear_menu()
                        return MenuSelection(selected=False, cancelled=True)

                # Handle Enter key
                elif char in ('\r', '\n'):  # Enter
                    selected_cmd = self.commands[self.selected_index]
                    self._clear_menu()
                    return MenuSelection(
                        selected=True,
                        command=selected_cmd.name,
                        cancelled=False,
                    )

                # Handle Ctrl+C
                elif char == '\x03':  # Ctrl+C
                    self._clear_menu()
                    raise KeyboardInterrupt

        finally:
            # Restore terminal settings
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

    def _move_selection(self, delta: int) -> None:
        """
        Move selection up or down.

        Args:
            delta: -1 for up, +1 for down
        """
        self.selected_index = (self.selected_index + delta) % len(self.commands)

    def _render_menu(self) -> None:
        """Render menu to console"""
        # Clear previous render (move cursor up)
        if hasattr(self, '_last_render_lines'):
            # Move cursor up and clear
            self.console.print(f"\033[{self._last_render_lines}A", end="")
            self.console.print("\033[J", end="")  # Clear from cursor to end

        # Create table
        table = self._create_table()

        # Wrap in panel
        panel = Panel(
            table,
            title=f"[bold cyan]Slash Commands ({len(self.commands)})[/bold cyan]",
            subtitle="[dim]Navigation: ↑/↓ • Enter to select • Esc to cancel[/dim]",
            border_style="blue",
            padding=(1, 2),
        )

        # Render
        self.console.print(panel)

        # Track lines for clearing later (approximate)
        self._last_render_lines = min(len(self.commands) + 6, 20)

    def _create_table(self) -> Table:
        """Create Rich Table with commands"""
        table = Table(
            show_header=False,
            show_edge=False,
            padding=(0, 1),
            box=None,
            expand=True,
        )

        # Columns: Selection indicator, Command name, Description, Aliases
        table.add_column("", width=2, style="")
        table.add_column("Command", width=12, style="cyan")
        table.add_column("Description", width=40, style="white")
        table.add_column("Aliases", width=12, style="dim")

        # Add command rows
        for i, cmd in enumerate(self.commands):
            is_selected = (i == self.selected_index)

            # Format row
            indicator = "[bold green]>[/bold green]" if is_selected else " "
            name_style = "bold cyan" if is_selected else "cyan"
            desc_style = "bold white" if is_selected else "white"

            # Format aliases
            aliases_str = ", ".join(cmd.aliases) if cmd.aliases else ""

            # Add row
            table.add_row(
                indicator,
                f"[{name_style}]{cmd.name}[/{name_style}]",
                f"[{desc_style}]{cmd.description}[/{desc_style}]",
                f"[dim]{aliases_str}[/dim]",
            )

        return table

    def _clear_menu(self) -> None:
        """Clear menu from screen"""
        if hasattr(self, '_last_render_lines'):
            # Move cursor up and clear
            self.console.print(f"\033[{self._last_render_lines}A", end="")
            self.console.print("\033[J", end="")  # Clear from cursor to end
