"""Built-in slash commands for Navi Code TUI."""

from __future__ import annotations

from clients.terminal import api
from clients.terminal.config import settings
from clients.terminal.tui.commands.base import BaseCommand, CommandMeta
from clients.terminal.tui.context import TuiContext


class HelpCommand(BaseCommand):
    meta = CommandMeta(
        name="help",
        aliases=(),
        description="Show available slash commands.",
        keybind=None,
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        from clients.terminal.tui.commands.registry import get_registry

        registry = get_registry()
        lines = ["[b]Slash commands[/b]"]
        for cmd in registry.all():
            aliases = f" ({', '.join(cmd.meta.aliases)})" if cmd.meta.aliases else ""
            key = f" [{cmd.meta.keybind}]" if cmd.meta.keybind else ""
            lines.append(f"  /{cmd.meta.name}{aliases}{key} — {cmd.meta.description}")
        ctx.chat_panel.handle_ws_event({"type": "status", "content": "\n".join(lines)})


class NewCommand(BaseCommand):
    meta = CommandMeta(
        name="new",
        aliases=("clear",),
        description="Start a new session.",
        keybind="ctrl+x n",
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        try:
            session = api.create_session(settings.default_profile_id)
        except Exception as exc:
            ctx.chat_panel.handle_ws_event({"type": "error", "message": f"Failed to create session: {exc}"})
            return
        ctx.session_id = session["id"]
        ctx.profile_id = session.get("profile_id")
        ctx.state.set_session_id(session["id"])
        ctx.status_panel.set_session(session["id"])
        ctx.status_panel.set_profile(ctx.profile_id or settings.default_profile_id)
        ctx.chat_panel.handle_ws_event({"type": "status", "content": f"Created session {session['id'][:8]}"})
        await _reconnect_ws(ctx)


class SessionsCommand(BaseCommand):
    meta = CommandMeta(
        name="sessions",
        aliases=("resume", "continue"),
        description="List and switch between sessions.",
        keybind="ctrl+x l",
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        try:
            sessions = api.list_sessions()
        except Exception as exc:
            ctx.chat_panel.handle_ws_event({"type": "error", "message": f"Failed to list sessions: {exc}"})
            return
        lines = ["[b]Sessions[/b]"]
        for s in sessions:
            marker = "● " if s["id"] == ctx.session_id else "  "
            lines.append(f"{marker}{s['id'][:8]}  {s.get('profile_id', 'unknown')}  {s.get('title', '')}")
        ctx.chat_panel.handle_ws_event({"type": "status", "content": "\n".join(lines)})


class SwitchCommand(BaseCommand):
    meta = CommandMeta(
        name="switch",
        aliases=(),
        description="Switch to another session by id or prefix.",
        keybind=None,
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        target = args.strip()
        if not target:
            ctx.chat_panel.handle_ws_event({"type": "error", "message": "Usage: /switch <session_id_or_prefix>"})
            return
        try:
            session = api.get_session(target)
        except Exception:
            try:
                sessions = api.list_sessions()
                matches = [s for s in sessions if s["id"].startswith(target)]
                if len(matches) == 1:
                    session = matches[0]
                else:
                    raise Exception("no unique match")
            except Exception as exc:
                ctx.chat_panel.handle_ws_event({"type": "error", "message": f"Session not found: {target} ({exc})"})
                return
        ctx.session_id = session["id"]
        ctx.profile_id = session.get("profile_id")
        ctx.state.set_session_id(session["id"])
        ctx.status_panel.set_session(session["id"])
        ctx.status_panel.set_profile(ctx.profile_id or settings.default_profile_id)
        ctx.chat_panel.handle_ws_event({"type": "status", "content": f"Switched to {session['id'][:8]}"})
        await _reconnect_ws(ctx)


class ProfileCommand(BaseCommand):
    meta = CommandMeta(
        name="profile",
        aliases=(),
        description="Show current session profile.",
        keybind=None,
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        if not ctx.session_id:
            ctx.chat_panel.handle_ws_event({"type": "error", "message": "No active session"})
            return
        try:
            session = api.get_session(ctx.session_id)
        except Exception as exc:
            ctx.chat_panel.handle_ws_event({"type": "error", "message": f"Failed to get session: {exc}"})
            return
        ctx.chat_panel.handle_ws_event(
            {"type": "status", "content": f"Profile: {session.get('profile_id')}\nSession: {session['id']}"}
        )


class QuitCommand(BaseCommand):
    meta = CommandMeta(
        name="quit",
        aliases=("exit", "q"),
        description="Exit Navi Code.",
        keybind="ctrl+x q",
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        app = ctx.app()
        app.exit()


class ThinkingCommand(BaseCommand):
    meta = CommandMeta(
        name="thinking",
        aliases=(),
        description="Toggle thinking block visibility.",
        keybind=None,
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        settings.show_thinking = not settings.show_thinking
        ctx.chat_panel.handle_ws_event(
            {"type": "status", "content": f"Thinking blocks: {'on' if settings.show_thinking else 'off'}"}
        )


class CompactCommand(BaseCommand):
    meta = CommandMeta(
        name="compact",
        aliases=(),
        description="Compact the current session (ask model to summarize context).",
        keybind="ctrl+x c",
    )

    async def execute(self, ctx: TuiContext, args: str) -> None:
        if ctx.ws_client:
            ctx.ws_client.enqueue("Please summarize and compact our conversation so far.")


async def _reconnect_ws(ctx: TuiContext) -> None:
    """Close old WebSocket and open a new one for the current session."""
    if ctx.ws_client:
        await ctx.ws_client.close()
    if not ctx.session_id:
        return
    from clients.terminal.tui.events import ConnectionStatusChanged
    from clients.terminal.ws_client import NaviWebSocketClient

    new_client = NaviWebSocketClient(ctx.session_id)
    ctx.ws_client = new_client
    try:
        await new_client.connect()
        app = ctx.app()
        app.run_worker(new_client.receive_loop)
        ctx.status_panel.set_connection(True, "")
        app.post_message(ConnectionStatusChanged(True, ""))
    except Exception as exc:
        ctx.status_panel.set_connection(False, str(exc))
        ctx.app().post_message(ConnectionStatusChanged(False, str(exc)))
