"""
Interactive CLI - Real-time command menu like Claude Code.

Provides an interactive prompt that:
- Shows command menu immediately when "/" is typed
- Allows filtering by typing more characters
- Supports arrow key navigation
- Executes command on Enter
"""

from html import escape as html_escape
from typing import Optional, Callable, Awaitable, List, Tuple
from dataclasses import dataclass

from prompt_toolkit import PromptSession
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.keys import Keys
from prompt_toolkit.styles import Style
from prompt_toolkit.formatted_text import HTML, FormattedText
from prompt_toolkit.application import get_app

from .menu import COMMANDS, Command


# Style for the prompt
PROMPT_STYLE = Style.from_dict({
    'prompt': '#00d7ff bold',        # Cyan for prompt
    'command': '#00ff00 bold',       # Bright green for commands (high contrast)
    'description': '#d0d0d0',        # Light gray for descriptions (better contrast)
    'selected': 'bg:#005f87 #ffffff',  # Blue background, white text for selected
    'category': '#af87ff',           # Purple for category
    'args': '#87afff',               # Light blue for arguments
    # Completion menu styles
    'completion-menu': 'bg:#1c1c1c #d0d0d0',  # Dark bg, light text
    'completion-menu.completion': 'bg:#1c1c1c #00ff00',  # Green commands
    'completion-menu.completion.current': 'bg:#005f87 #ffffff bold',  # Blue bg for selected
    'completion-menu.meta': 'bg:#1c1c1c #87afff',  # Light blue for meta/description
    'completion-menu.meta.current': 'bg:#005f87 #ffffff',  # White meta when selected
})


class CommandCompleter(Completer):
    """
    Autocomplete for orchestrator commands.

    Shows command suggestions as the user types, with descriptions.
    """

    def __init__(self, commands: List[Command]):
        self.commands = commands
        # Build a lookup for unique commands (some have same name, different args)
        self._unique_commands = {}
        for cmd in commands:
            if cmd.name not in self._unique_commands:
                self._unique_commands[cmd.name] = cmd

    def get_completions(self, document, complete_event):
        """Generate completions for the current input."""
        text = document.text_before_cursor

        # Only show completions if starting with "/"
        if not text.startswith('/'):
            return

        # Filter commands based on what's typed
        search = text.lower()

        for cmd_name, cmd in self._unique_commands.items():
            if cmd_name.lower().startswith(search):
                # Calculate what to insert (remove already typed part)
                insert_text = cmd_name[len(text):]

                # Build display with args
                display = cmd_name
                if cmd.args:
                    display = f"{cmd_name} {cmd.args}"

                # Escape HTML special characters to prevent XML parsing errors
                safe_display = html_escape(display)
                safe_description = html_escape(cmd.description)

                yield Completion(
                    insert_text,
                    start_position=0,
                    display=HTML(f'<command>{safe_display}</command>'),
                    display_meta=HTML(f'<description>{safe_description}</description>'),
                    style='class:command',
                    selected_style='class:selected',
                )


class InteractivePrompt:
    """
    Interactive prompt with real-time command menu.

    Features:
    - "/" triggers command autocomplete menu
    - Arrow keys to navigate
    - Tab to complete
    - Enter to execute
    """

    def __init__(self):
        self.completer = CommandCompleter(COMMANDS)
        self.session = PromptSession(
            completer=self.completer,
            complete_while_typing=True,
            style=PROMPT_STYLE,
            complete_in_thread=True,
        )

    def get_prompt_text(self) -> FormattedText:
        """Get the formatted prompt text."""
        return FormattedText([
            ('class:prompt', 'orchestrator'),
            ('', ' '),
            ('class:prompt', '❯'),
            ('', ' '),
        ])

    async def prompt_async(self) -> str:
        """
        Show the interactive prompt and return user input.

        Returns:
            The user's input string
        """
        return await self.session.prompt_async(
            self.get_prompt_text(),
        )

    def prompt(self) -> str:
        """
        Show the interactive prompt (synchronous version).

        Returns:
            The user's input string
        """
        return self.session.prompt(
            self.get_prompt_text(),
        )


class SlashMenuPrompt:
    """
    A more Claude Code-like slash menu that appears as a popup.

    Shows a navigable menu when "/" is typed.
    """

    def __init__(self):
        self.commands = COMMANDS
        self.selected_index = 0
        self.filter_text = ""
        self._filtered_commands: List[Command] = []

        # Key bindings
        self.bindings = KeyBindings()
        self._setup_bindings()

        # Session
        self.session = PromptSession(
            key_bindings=self.bindings,
            style=PROMPT_STYLE,
        )

    def _setup_bindings(self):
        """Set up custom key bindings."""

        @self.bindings.add(Keys.Up)
        def move_up(event):
            if self.selected_index > 0:
                self.selected_index -= 1

        @self.bindings.add(Keys.Down)
        def move_down(event):
            if self.selected_index < len(self._filtered_commands) - 1:
                self.selected_index += 1

        @self.bindings.add(Keys.Tab)
        def complete_command(event):
            if self._filtered_commands:
                cmd = self._filtered_commands[self.selected_index]
                # Replace buffer with selected command
                event.app.current_buffer.text = cmd.name + " "
                event.app.current_buffer.cursor_position = len(event.app.current_buffer.text)

        @self.bindings.add(Keys.Escape)
        def cancel(event):
            event.app.current_buffer.text = ""
            event.app.exit(result="")

    def _filter_commands(self, text: str) -> List[Command]:
        """Filter commands based on input text."""
        if not text or text == "/":
            return list({c.name: c for c in self.commands}.values())

        search = text.lower().lstrip('/')
        seen = set()
        result = []
        for cmd in self.commands:
            if cmd.name not in seen:
                if search in cmd.name.lower() or search in cmd.description.lower():
                    result.append(cmd)
                    seen.add(cmd.name)
        return result

    def get_bottom_toolbar(self) -> str:
        """Get toolbar showing available commands."""
        if not self.filter_text.startswith('/'):
            return ''

        self._filtered_commands = self._filter_commands(self.filter_text)
        if not self._filtered_commands:
            return '<description>No matching commands</description>'

        # Build menu display
        lines = []
        max_display = min(8, len(self._filtered_commands))

        # Adjust view window around selected index
        start = max(0, self.selected_index - 3)
        end = min(len(self._filtered_commands), start + max_display)

        for i in range(start, end):
            cmd = self._filtered_commands[i]
            if i == self.selected_index:
                prefix = ">"
            else:
                prefix = " "

            args_str = f" {cmd.args}" if cmd.args else ""
            lines.append(f"{prefix} {cmd.name}{args_str} - {cmd.description}")

        return "\n".join(lines)


def create_interactive_session() -> PromptSession:
    """
    Create a prompt session with command completion.

    Returns:
        Configured PromptSession
    """
    completer = CommandCompleter(COMMANDS)

    return PromptSession(
        completer=completer,
        complete_while_typing=True,
        style=PROMPT_STYLE,
    )


# Convenience function for the main module
_session: Optional[PromptSession] = None


def get_interactive_session() -> PromptSession:
    """Get or create the global interactive session."""
    global _session
    if _session is None:
        _session = create_interactive_session()
    return _session


async def interactive_prompt(prompt_text: str = "orchestrator ❯ ") -> str:
    """
    Show an interactive prompt with command completion.

    Args:
        prompt_text: The prompt to display

    Returns:
        User input string
    """
    session = get_interactive_session()
    return await session.prompt_async(
        FormattedText([
            ('class:prompt', 'orchestrator'),
            ('', ' '),
            ('class:prompt', '❯'),
            ('', ' '),
        ])
    )
