"""Textual TUI application for Navi Code."""

from __future__ import annotations

from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.widgets import Footer, Header

from clients.terminal import api
from clients.terminal.config import settings
from clients.terminal.state import StateManager
from clients.terminal.tui.commands.registry import get_registry
from clients.terminal.tui.context import TuiContext
from clients.terminal.tui.events import (
    ConnectionStatusChanged,
    PermissionRequest,
    UserSubmitted,
    WsEvent,
)
from clients.terminal.tui.permissions import PermissionEngine
from clients.terminal.tui.widgets import ChatPanel, InputBox, StatusPanel
from clients.terminal.tui.ws_bridge import WsBridge


class NaviCodeTui(App):
    """OpenCode-inspired terminal UI for Navi."""

    CSS = """
    Screen { align: center middle; }
    NaviCodeTui { padding: 0; }
    Header { height: 1; }
    Footer { height: 1; }
    """

    BINDINGS = [
        ("ctrl+p", "command_palette", "Palette"),
        ("ctrl+x q", "quit", "Quit"),
        ("ctrl+x n", "new_session", "New"),
        ("ctrl+x l", "list_sessions", "Sessions"),
        ("ctrl+x c", "compact", "Compact"),
        ("ctrl+x t", "toggle_thinking", "Thinking"),
    ]

    def __init__(
        self,
        session_id: str | None = None,
        profile_id: str | None = None,
        new_session: bool = False,
    ) -> None:
        super().__init__()
        self._chat_panel = ChatPanel()
        self._status_panel = StatusPanel()
        self._input_box = InputBox()
        self._state = StateManager()
        self._ctx = TuiContext(
            state=self._state,
            chat_panel=self._chat_panel,
            status_panel=self._status_panel,
        )
        self._bridge: WsBridge | None = None
        self._permission_engine = PermissionEngine()
        self._pending_permission: PermissionRequest | None = None
        self._requested_session_id = session_id
        self._requested_profile_id = profile_id
        self._force_new_session = new_session

    def compose(self) -> ComposeResult:
        yield Header(show_clock=False)
        with Horizontal():
            yield self._chat_panel
            yield self._status_panel
        yield self._input_box
        yield Footer()

    def on_mount(self) -> None:
        self.run_worker(self._startup)

    async def _startup(self) -> None:
        session_id = await self._resolve_session(
            self._requested_session_id,
            self._requested_profile_id,
            self._force_new_session,
        )
        if session_id:
            await self._attach_session(session_id)
        self._input_box.focus_input()

    async def _resolve_session(
        self,
        session_id: str | None,
        profile_id: str | None,
        force_new: bool,
    ) -> str | None:
        if session_id and not force_new:
            try:
                session = api.get_session(session_id)
                return session["session_id"]
            except Exception:
                pass

        if not force_new:
            saved = self._state.get_session_id()
            if saved:
                try:
                    session = api.get_session(saved)
                    return session["session_id"]
                except Exception:
                    self._state.clear_session_id()

        profile = profile_id or settings.default_profile_id
        try:
            session = api.create_session(profile)
        except Exception as exc:
            self._chat_panel.handle_ws_event({"type": "error", "message": f"Failed to create session: {exc}"})
            return None
        self._state.set_session_id(session["session_id"])
        return session["session_id"]

    async def _attach_session(self, session_id: str) -> None:
        self._ctx.session_id = session_id
        try:
            session = api.get_session(session_id)
            self._ctx.profile_id = session.get("profile_id") or settings.default_profile_id
        except Exception:
            self._ctx.profile_id = settings.default_profile_id

        self._status_panel.set_session(session_id)
        self._status_panel.set_profile(self._ctx.profile_id)
        self._status_panel.set_model(settings.ollama_default_model if hasattr(settings, "ollama_default_model") else "unknown")

        if self._bridge:
            await self._bridge.stop()
        self._bridge = WsBridge(self, session_id)
        await self._bridge.start()
        self._ctx.ws_client = self._bridge.client
        self._chat_panel.handle_ws_event({"type": "status", "content": f"Connected to {session_id[:8]}"})

    def on_user_submitted(self, event: UserSubmitted) -> None:
        text = event.text
        if text.startswith("/"):
            self._run_command(text)
            return

        # @ file references and ! shell commands can be parsed here in Phase 4.
        self._chat_panel.add_user_message(text)
        if self._bridge and self._bridge.connected:
            self._bridge.client.enqueue(text)
        else:
            self._chat_panel.handle_ws_event({"type": "error", "message": "Not connected to a session"})

    def _run_command(self, text: str) -> None:
        parts = text[1:].split(None, 1)
        name = parts[0].lower()
        args = parts[1] if len(parts) > 1 else ""
        registry = get_registry()
        cmd = registry.get(name)
        if cmd is None:
            self._chat_panel.handle_ws_event({"type": "error", "message": f"Unknown command: /{name}"})
            return
        self.run_worker(self._command_worker(cmd, args))

    async def _command_worker(self, cmd, args: str) -> None:
        await cmd.execute(self._ctx, args)

    def on_ws_event(self, event: WsEvent) -> None:
        self._chat_panel.handle_ws_event(event.payload)

    def on_connection_status_changed(self, event: ConnectionStatusChanged) -> None:
        self._status_panel.set_connection(event.connected, event.detail)

    def on_permission_request(self, event: PermissionRequest) -> None:
        self._pending_permission = event
        self._chat_panel.handle_ws_event(
            {
                "type": "status",
                "content": f"Permission required: {event.details}\nAllow once (y) / always (a) / reject (n)",
            }
        )

    def action_command_palette(self) -> None:
        # Phase 4: implement command palette screen.
        self._chat_panel.handle_ws_event({"type": "status", "content": "Command palette: /help, /new, /sessions, /switch, /profile, /thinking, /compact, /quit"})

    def action_new_session(self) -> None:
        self._run_command("/new")

    def action_list_sessions(self) -> None:
        self._run_command("/sessions")

    def action_compact(self) -> None:
        self._run_command("/compact")

    def action_toggle_thinking(self) -> None:
        self._run_command("/thinking")

    async def action_quit(self) -> None:
        if self._bridge:
            await self._bridge.stop()
        self.exit()

    async def on_unmount(self) -> None:
        if self._bridge:
            await self._bridge.stop()
