"""Input mode router for TUI prompt handling."""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from enum import StrEnum

from cleveragents.tui.input.reference_parser import (
    ReferenceParseResult,
    parse_references,
)
from cleveragents.tui.input.shell_exec import ShellResult, run_shell_command


class InputMode(StrEnum):
    """Prompt input mode."""

    NORMAL = "normal"
    COMMAND = "command"
    SHELL = "shell"


@dataclass(slots=True, frozen=True)
class ModeResult:
    """Mode-router output."""

    mode: InputMode
    expanded_text: str
    references: list[str]
    shell_result: ShellResult | None
    command_result: str | None


class InputModeRouter:
    """Dispatch user input to normal/command/shell handlers."""

    def __init__(
        self,
        command_handler: Callable[[str], str],
        *,
        shell_confirm: Callable[[str], bool] | None = None,
        shell_timeout_seconds: int = 30,
    ) -> None:
        self._command_handler = command_handler
        self._shell_confirm = shell_confirm
        self._shell_timeout_seconds = shell_timeout_seconds

    @staticmethod
    def detect_mode(text: str) -> InputMode:
        stripped = text.lstrip()
        if stripped.startswith("/"):
            return InputMode.COMMAND
        if stripped.startswith("!"):
            return InputMode.SHELL
        return InputMode.NORMAL

    def process(self, text: str) -> ModeResult:
        mode = self.detect_mode(text)
        if mode == InputMode.COMMAND:
            cmd = text.lstrip()[1:]
            result = self._command_handler(cmd)
            return ModeResult(
                mode=mode,
                expanded_text=text,
                references=[],
                shell_result=None,
                command_result=result,
            )
        if mode == InputMode.SHELL:
            command = text.lstrip()[1:].strip()
            shell_result = run_shell_command(
                command,
                confirm_dangerous=self._shell_confirm,
                timeout_seconds=self._shell_timeout_seconds,
            )
            return ModeResult(
                mode=mode,
                expanded_text=text,
                references=[],
                shell_result=shell_result,
                command_result=None,
            )

        parse_result: ReferenceParseResult = parse_references(text)
        return ModeResult(
            mode=mode,
            expanded_text=parse_result.expanded_line,
            references=[match.canonical for match in parse_result.matches],
            shell_result=None,
            command_result=None,
        )
