"""Textual TUI application shell."""

from __future__ import annotations

import importlib
import os
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, ClassVar, Protocol

from cleveragents.tui.first_run import create_default_persona_for_actor, is_first_run
from cleveragents.tui.input.modes import InputMode, InputModeRouter
from cleveragents.tui.input.reference_parser import suggestions
from cleveragents.tui.persona.state import PersonaState
from cleveragents.tui.slash_catalog import slash_command_specs
from cleveragents.tui.widgets.actor_selection_overlay import ActorSelectionOverlay
from cleveragents.tui.widgets.help_panel_overlay import (
    HelpPanelOverlay,
    resolve_help_context,
)
from cleveragents.tui.widgets.persona_bar import PersonaBar
from cleveragents.tui.widgets.prompt import PromptInput
from cleveragents.tui.widgets.reference_picker import ReferencePickerOverlay
from cleveragents.tui.widgets.slash_command_overlay import SlashCommandOverlay

if TYPE_CHECKING:
    InputSubmittedEvent = Any
else:
    InputSubmittedEvent = Any

_TEXTUAL_AVAILABLE = False
_TextualApp: type[Any] = object
_Vertical: type[Any] = object
_Header: type[Any] = object
_Footer: type[Any] = object
_Static: type[Any] = object
try:  # pragma: no branch - import gate for optional dependency
    _textual_app = importlib.import_module("textual.app")
    _textual_containers = importlib.import_module("textual.containers")
    _textual_widgets = importlib.import_module("textual.widgets")
    _TextualApp = _textual_app.App
    _Vertical = _textual_containers.Vertical
    _Header = _textual_widgets.Header
    _Footer = _textual_widgets.Footer
    _Static = _textual_widgets.Static
    _TEXTUAL_AVAILABLE = True
except Exception:  # pragma: no cover
    _TEXTUAL_AVAILABLE = False


def textual_available() -> bool:
    """Return whether Textual import succeeded."""
    return _TEXTUAL_AVAILABLE


@dataclass(slots=True)
class SessionView:
    """Minimal per-session TUI view model."""

    session_id: str
    transcript: list[str]


class _CommandRouter(Protocol):
    """Router protocol used by the TUI input-mode command handler."""

    def handle(self, raw: str, *, session_id: str) -> str:
        """Dispatch a slash command and return a rendered response."""
        ...


class _FallbackCleverAgentsTuiApp:  # pragma: no cover
    """Fallback app that raises actionable dependency error."""

    def __init__(
        self, *, command_router: _CommandRouter, persona_state: PersonaState
    ) -> None:
        del command_router, persona_state

    def run(self) -> None:
        raise RuntimeError(
            "Textual dependency missing. Install with: pip install 'cleveragents[tui]'"
        )


_ResolvedTuiApp: type[Any] = _FallbackCleverAgentsTuiApp
if _TEXTUAL_AVAILABLE:

    class _TextualCleverAgentsTuiApp(_TextualApp):
        """Main TUI app."""

        CSS_PATH: ClassVar[str] = "cleveragents.tcss"
        BINDINGS: ClassVar[list[tuple[str, str, str]]] = [
            ("ctrl+q", "quit", "Quit"),
            ("f1", "help", "Help"),
            ("ctrl+t", "cycle_preset", "Cycle Preset"),
        ]

        def __init__(
            self,
            *,
            command_router: _CommandRouter,
            persona_state: PersonaState,
        ) -> None:
            super().__init__()
            self._command_router = command_router
            self._persona_state = persona_state
            self._session = SessionView(session_id="default", transcript=[])

        def compose(self) -> Any:
            yield _Header(show_clock=True)
            with _Vertical(id="main-column"):
                yield _Static("CleverAgents TUI", id="conversation")
                yield HelpPanelOverlay(id="help-panel")
                yield ReferencePickerOverlay(id="reference-picker")
                yield SlashCommandOverlay(id="slash-overlay")
                yield ActorSelectionOverlay(id="actor-selection")
                yield PromptInput(
                    placeholder="Type message, /command, or !shell ...", id="prompt"
                )
                yield PersonaBar(id="persona-bar")
            yield _Footer()

        def on_mount(self) -> None:
            # Check first-run BEFORE _refresh_persona_bar, which calls
            # ensure_default() and would create a persona, masking the check.
            first_run = is_first_run(self._persona_state.registry)
            self._refresh_persona_bar()
            help_panel = self.query_one("#help-panel", HelpPanelOverlay)
            help_panel.hide()
            ref_picker = self.query_one("#reference-picker", ReferencePickerOverlay)
            ref_picker.set_suggestions("", [])
            slash = self.query_one("#slash-overlay", SlashCommandOverlay)
            slash.set_commands("", slash_command_specs())
            actor_overlay = self.query_one("#actor-selection", ActorSelectionOverlay)
            if first_run:
                actor_overlay.show()
            else:
                actor_overlay.hide()

        def _complete_first_run(self, actor: str) -> None:
            """Persist the chosen actor as the default persona and refresh the bar."""
            create_default_persona_for_actor(self._persona_state.registry, actor)
            self._refresh_persona_bar()

        def action_help(self) -> None:
            prompt = self.query_one("#prompt", PromptInput)
            help_panel = self.query_one("#help-panel", HelpPanelOverlay)
            context_name = resolve_help_context(prompt.value)
            help_panel.toggle(context_name)

        def action_cycle_preset(self) -> None:
            self._persona_state.cycle_preset(self._session.session_id)
            self._refresh_persona_bar()

        def _refresh_persona_bar(self) -> None:
            persona = self._persona_state.active_persona(self._session.session_id)
            preset = self._persona_state.current_preset(self._session.session_id)
            scope_count = len(persona.scoped_projects) + len(persona.scoped_plans)
            scope_text = f"{scope_count} scope refs"
            bar = self.query_one("#persona-bar", PersonaBar)
            bar.set_content(
                persona_name=persona.name,
                actor_name=persona.actor,
                preset_name=preset,
                scope_text=scope_text,
            )

        def on_input_submitted(self, event: InputSubmittedEvent) -> None:
            del event
            prompt = self.query_one("#prompt", PromptInput)
            payload = prompt.consume_text()
            text = payload.text.strip()
            if not text:
                return

            mode_router = InputModeRouter(
                command_handler=lambda raw: self._command_router.handle(
                    raw, session_id=self._session.session_id
                ),
                shell_confirm=lambda _cmd: (
                    os.environ.get("CLEVERAGENTS_ALLOW_DANGEROUS_SHELL", "").strip()
                    in {"1", "true"}
                ),
            )
            result = mode_router.process(text)
            conversation = self.query_one("#conversation", _Static)

            if result.mode == InputMode.COMMAND:
                conversation.update(result.command_result or "")
                self._refresh_persona_bar()
                return
            if result.mode == InputMode.SHELL:
                shell = result.shell_result
                if shell is None:
                    conversation.update("(no shell output)")
                    return
                output = (
                    shell.stdout.strip() or shell.stderr.strip() or "(empty output)"
                )
                conversation.update(f"$ {shell.command}\n{output}")
                return

            preview = result.expanded_text
            if "@" in text:
                ref_picker = self.query_one("#reference-picker", ReferencePickerOverlay)
                ref_picker.set_suggestions(
                    text, suggestions(text.replace("@", "").strip())
                )
            conversation.update(preview)

    _ResolvedTuiApp = _TextualCleverAgentsTuiApp

CleverAgentsTuiApp = _ResolvedTuiApp
