"""Tool Configs screen for browsing and managing tool configurations.

This screen provides:
- Search and browse tool configs
- View tool config details in preview panel (including JSON config)
- Create new tool configs
- Edit existing tool configs
- Delete tool configs (with in-use protection)
"""

from typing import TYPE_CHECKING

from rich.markup import escape
from textual import on, work
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.widgets import Button, DataTable, Input, Static

from alloy_runtime_types.dtos.tool_configs import ToolConfigSummary

from cli.infrastructure.scope_utils import format_scope_label
from cli.infrastructure.tui.clipboard import copy_to_clipboard
from cli.infrastructure.tui.formatters import format_datetime
from cli.tui.screens.base import BrowserWidget
from cli.tui.screens.nav_screen import NavScreen
from cli.tui.widgets.confirm_modal import ConfirmModal
from cli.tui.widgets.tool_config_create_modal import (
    ToolConfigCreateModal,
    ToolConfigCreateResult,
)
from cli.tui.widgets.tool_config_update_modal import ToolConfigUpdateModal

if TYPE_CHECKING:
    from cli.tui.app import AlloyRuntimeApp


class ToolConfigsWidget(BrowserWidget[ToolConfigSummary]):
    """Widget for browsing and managing tool configurations."""

    app: "AlloyRuntimeApp"

    TITLE = "Tool Configs"
    TABLE_COLUMNS = ["Name", "Tool", "Scope", "Updated"]

    def compose(self) -> ComposeResult:
        """Compose the browser layout with a New button."""
        with Vertical(id="browser-root"):
            with Vertical(id="search-container"):
                with Horizontal(id="search-row"):
                    yield Input(
                        placeholder=f"Search {self.TITLE.lower()}...",
                        id="search-input",
                    )
                    yield Button("+ New", id="new-config-btn", variant="primary")
                yield Static("Loading...", id="status-bar")

            with Horizontal(id="main-container"):
                with Vertical(id="list-container"):
                    yield DataTable(id="data-table", cursor_type="row")

                with Vertical(id="detail-container"):
                    yield Static("Preview", id="preview-title")
                    with VerticalScroll(id="preview-scroll"):
                        yield Static(
                            "Select an item to view details",
                            id="preview-content",
                        )

    @on(Button.Pressed, "#new-config-btn")
    def _on_new_config_btn_pressed(self, event: Button.Pressed) -> None:
        """Handle New button press."""
        self.open_new_modal()

    async def _fetch_items(self, query: str) -> tuple[list[ToolConfigSummary], int]:
        """Fetch tool configs from the API."""
        client = await self._ensure_client()
        response = await client.list_tool_configs(
            search=query if query else None,
            limit=50,
        )
        return list(response.tool_configs), response.total

    def _format_row(self, item: ToolConfigSummary) -> tuple[str, ...]:
        """Format a tool config as a table row."""
        return (
            item.name,
            item.tool_id,
            format_scope_label(
                str(item.organization_id) if item.organization_id else None,
                str(item.user_id) if item.user_id else None,
            ),
            format_datetime(item.updated_at),
        )

    def _update_preview(self, item: ToolConfigSummary) -> None:
        """Update the preview pane with tool config details.

        Note: ToolConfigSummary doesn't include the full config JSON.
        We show the basic info here. For full config, user can edit.
        """
        preview = self.query_one("#preview-content", Static)

        scope = format_scope_label(
            str(item.organization_id) if item.organization_id else None,
            str(item.user_id) if item.user_id else None,
        )

        created = format_datetime(item.created_at)
        updated = format_datetime(item.updated_at)

        preview_text = f"""[bold]Tool Config ID:[/] {escape(str(item.id))}
[bold]Name:[/] {escape(item.name)}
[bold]Slug:[/] {escape(item.slug)}
[bold]Tool:[/] {escape(item.tool_id)}
[bold]Scope:[/] {scope}

[bold]Description:[/]
{escape(item.description or "(no description)")}

[dim]Note: Edit to view full configuration JSON[/]

[bold]Created:[/] {created}
[bold]Updated:[/] {updated}"""

        preview.update(preview_text)

    # =========================================================================
    # Public methods for parent Screen to call
    # =========================================================================

    def copy_config_name(self) -> None:
        """Copy the tool config name to clipboard."""
        config = self.get_selected_item()
        if not config:
            self.app.notify("No tool config selected", severity="warning")
            return

        copy_to_clipboard(self.app, config.name, "Tool config name")

    def open_new_modal(self) -> None:
        """Open the tool config creation modal."""
        self._open_create_modal()

    def open_edit_modal(self) -> None:
        """Open the tool config update modal for the selected config."""
        config = self.get_selected_item()
        if not config:
            self.app.notify("No tool config selected", severity="warning")
            return
        self._open_update_modal(config)

    def delete_selected(self) -> None:
        """Delete the currently selected tool config."""
        config = self.get_selected_item()
        if not config:
            self.app.notify("No tool config selected", severity="warning")
            return

        config_name = config.name
        self.app.push_screen(
            ConfirmModal(
                title="Delete Tool Config",
                message=f"Delete tool config '{config_name}'?\n\n"
                "Note: Deletion will fail if this config is used by any agents.",
            ),
            lambda confirmed: self._on_delete_confirmed(confirmed, str(config.id)),
        )

    # =========================================================================
    # Internal async operations
    # =========================================================================

    @work(exclusive=True)
    async def _open_create_modal(self) -> None:
        """Open the tool config creation modal."""
        try:
            client = await self._ensure_client()
            self.app.push_screen(
                ToolConfigCreateModal(client=client),
                self._on_config_created,
            )
        except Exception as e:
            self.app.notify(f"Failed to open config creator: {e}", severity="error")

    def _on_config_created(self, result: ToolConfigCreateResult | None) -> None:
        """Callback when tool config creation modal is dismissed."""
        if result is not None:
            self.app.notify(
                f"Created tool config: {result.config_name}",
                severity="information",
            )
            # Refresh the list
            self._do_search(self._last_search)

    @work(exclusive=True)
    async def _open_update_modal(self, config_summary: ToolConfigSummary) -> None:
        """Fetch full tool config details and open the update modal."""
        try:
            client = await self._ensure_client()
            # Fetch full config (includes the config JSON)
            config = await client.get_tool_config(str(config_summary.id))
            self.app.push_screen(
                ToolConfigUpdateModal(client=client, config=config),
                self._on_config_updated,
            )
        except Exception as e:
            self.app.notify(f"Failed to open config editor: {e}", severity="error")

    def _on_config_updated(self, result: ToolConfigCreateResult | None) -> None:
        """Callback when tool config update modal is dismissed."""
        if result is not None:
            self.app.notify(
                f"Updated tool config: {result.config_name}",
                severity="information",
            )
            # Refresh the list
            self._do_search(self._last_search)

    def _on_delete_confirmed(self, confirmed: bool | None, config_id: str) -> None:
        """Callback when delete confirmation modal is dismissed."""
        if confirmed:
            self._execute_delete(config_id)

    @work(exclusive=True)
    async def _execute_delete(self, config_id: str) -> None:
        """Execute the delete operation."""
        try:
            client = await self._ensure_client()
            response = await client.delete_tool_config(config_id)

            self.app.notify(
                f"Tool config '{response.deleted_tool_config.name}' deleted",
                severity="information",
            )
            # Refresh the list
            self._do_search(self._last_search)

        except Exception as e:
            error_msg = str(e)
            if "in use" in error_msg.lower() or "referenced" in error_msg.lower():
                self.app.notify(
                    "Cannot delete: config is used by one or more agents",
                    severity="error",
                )
            else:
                self.app.notify(f"Failed to delete tool config: {e}", severity="error")


class ToolConfigsScreen(NavScreen):
    """Screen for browsing and managing tool configurations.

    This is a proper Textual Screen that wraps the ToolConfigsWidget
    and provides keybindings that work regardless of focus.
    """

    app: "AlloyRuntimeApp"

    SCREEN_ID = "tool_configs"

    DEFAULT_CSS = """
    ToolConfigsScreen #screen-root {
        height: 1fr;
    }

    ToolConfigsScreen .browser-widget {
        height: 100%;
        width: 100%;
    }
    """

    # Screen-specific bindings (Ctrl+ prefixed)
    # NavScreen.BINDINGS provides global navigation (c, a, t, s, m, d, g, ?)
    BINDINGS = NavScreen.BINDINGS + [
        Binding("ctrl+f", "focus_search", "Search", show=True),
        Binding("ctrl+r", "refresh", "Refresh", show=True),
        Binding("ctrl+y", "copy_name", "Copy Name", show=True),
        Binding("ctrl+n", "new_config", "New", show=True),
        Binding("ctrl+e", "edit_config", "Edit", show=True),
        Binding("ctrl+d", "delete_config", "Delete", show=True),
        Binding("escape", "focus_table", "Focus List", show=False),
        Binding("enter", "copy_name", "Copy Name", show=False),
    ]

    def compose_content(self) -> ComposeResult:
        """Compose the screen content."""
        yield ToolConfigsWidget(id="tool-configs-widget")

    def on_screen_resume(self) -> None:
        """Focus the data table when screen becomes active."""
        self.call_after_refresh(self._focus_table)

    def _focus_table(self) -> None:
        """Focus the data table."""
        try:
            widget = self.query_one("#tool-configs-widget", ToolConfigsWidget)
            widget.focus_table()
        except Exception:
            pass

    def _get_widget(self) -> ToolConfigsWidget:
        """Get the tool configs widget."""
        return self.query_one("#tool-configs-widget", ToolConfigsWidget)

    # =========================================================================
    # Actions (keybinding handlers)
    # =========================================================================

    def action_focus_search(self) -> None:
        """Focus the search input."""
        self._get_widget().focus_search()

    def action_focus_table(self) -> None:
        """Focus the data table."""
        self._get_widget().focus_table()

    def action_refresh(self) -> None:
        """Refresh the current search results."""
        self._get_widget().refresh_data()

    def action_copy_name(self) -> None:
        """Copy the tool config name to clipboard."""
        self._get_widget().copy_config_name()

    def action_new_config(self) -> None:
        """Open the tool config creation modal."""
        self._get_widget().open_new_modal()

    def action_edit_config(self) -> None:
        """Open the tool config update modal."""
        self._get_widget().open_edit_modal()

    def action_delete_config(self) -> None:
        """Delete the selected tool config."""
        self._get_widget().delete_selected()
