"""Agent tools manager widget for managing a list of tool configurations.

Provides a compound widget for managing multiple tool configurations including:
- Add tool button
- List of AgentToolEditor widgets
- Removal of individual tools
- Validation of unique aliases
"""

from typing import Any

from textual import on
from textual.app import ComposeResult
from textual.containers import Vertical, VerticalScroll
from textual.message import Message
from textual.widget import Widget
from textual.widgets import Button, Static

from alloy_runtime_sdk.api_client.client import ApiClient
from alloy_runtime_types.dtos.agents import AgentToolConfig, AgentToolResponse

from cli.infrastructure.forms.agent_tool_editor import AgentToolEditor


class AgentToolsManager(Widget):
    """Manager widget for a list of agent tool configurations.

    Provides UI for managing multiple tool instances with:
    - Add tool button
    - List of AgentToolEditor widgets
    - Removal of individual tools
    - Validation of unique aliases

    Usage:
        manager = AgentToolsManager(client=client, id="tools-manager")
        # Get all configured tools
        tools = manager.configured_tools  # list[AgentToolConfig]
    """

    DEFAULT_CLASSES = "tools-manager"

    class ToolsChanged(Message):
        """Posted when the tools list changes."""

        def __init__(self, tools: list[AgentToolConfig]) -> None:
            self.tools = tools
            super().__init__()

    def __init__(
        self,
        client: ApiClient,
        **kwargs: Any,
    ) -> None:
        """Initialize the agent tools manager.

        Args:
            client: ApiClient instance for API calls
        """
        super().__init__(**kwargs)
        self._client = client
        self._editor_count = 0

    def compose(self) -> ComposeResult:
        with Vertical(classes="tools-manager-content"):
            yield Button("+ Add Tool", id="add-tool-btn", variant="primary")
            yield Static("No tools configured", id="empty-message")
            yield VerticalScroll(id="tools-list")

    @on(Button.Pressed, "#add-tool-btn")
    def on_add_tool_pressed(self, event: Button.Pressed) -> None:
        """Handle add tool button press."""
        event.stop()
        self._add_tool_editor()

    @on(AgentToolEditor.RemoveRequested)
    def on_tool_remove_requested(self, event: AgentToolEditor.RemoveRequested) -> None:
        """Handle tool removal request."""
        event.stop()
        self._remove_tool_editor(event.editor)

    @on(AgentToolEditor.ToolChanged)
    def on_tool_changed(self, event: AgentToolEditor.ToolChanged) -> None:
        """Handle tool configuration change."""
        event.stop()
        self.post_message(self.ToolsChanged(self.configured_tools))

    def _add_tool_editor(self) -> None:
        """Add a new tool editor to the list."""
        tools_list = self.query_one("#tools-list", VerticalScroll)
        editor = AgentToolEditor(
            client=self._client,
            tool_order=self._editor_count,
            id=f"tool-editor-{self._editor_count}",
        )
        tools_list.mount(editor)
        self._editor_count += 1
        self._update_empty_message()
        self.post_message(self.ToolsChanged(self.configured_tools))

    def _remove_tool_editor(self, editor: AgentToolEditor) -> None:
        """Remove a tool editor from the list."""
        editor.remove()
        self._renumber_editors()
        self._update_empty_message()
        self.post_message(self.ToolsChanged(self.configured_tools))

    def _renumber_editors(self) -> None:
        """Renumber all editors after removal."""
        tools_list = self.query_one("#tools-list", VerticalScroll)
        for i, editor in enumerate(tools_list.query(AgentToolEditor)):
            editor.set_tool_order(i)

    def _update_empty_message(self) -> None:
        """Show/hide empty message based on editor count."""
        tools_list = self.query_one("#tools-list", VerticalScroll)
        empty_message = self.query_one("#empty-message", Static)
        editors = list(tools_list.query(AgentToolEditor))
        if editors:
            empty_message.add_class("hidden")
        else:
            empty_message.remove_class("hidden")

    @property
    def configured_tools(self) -> list[AgentToolConfig]:
        """Get all configured tools.

        Returns:
            List of AgentToolConfig from all editors with valid selections
        """
        tools_list = self.query_one("#tools-list", VerticalScroll)
        configs: list[AgentToolConfig] = []
        for i, editor in enumerate(tools_list.query(AgentToolEditor)):
            config = editor.get_tool_config()
            if config:
                # Update tool_order to match current position
                config.tool_order = i
                configs.append(config)
        return configs

    def validate_aliases(self) -> str | None:
        """Validate that all tool aliases are unique.

        Returns:
            Error message if duplicates found, None if all unique
        """
        tools_list = self.query_one("#tools-list", VerticalScroll)
        aliases: dict[str, int] = {}

        for i, editor in enumerate(tools_list.query(AgentToolEditor)):
            alias = editor.get_alias()
            if not alias:
                continue
            if alias in aliases:
                return (
                    f"Duplicate tool alias '{alias}' found in tools "
                    f"#{aliases[alias] + 1} and #{i + 1}"
                )
            aliases[alias] = i

        return None

    def validate_all(self) -> str | None:
        """Validate all tool editors.

        Returns:
            First error message found, or None if all valid
        """
        tools_list = self.query_one("#tools-list", VerticalScroll)

        # Validate individual editors
        for editor in tools_list.query(AgentToolEditor):
            error = editor.validate()
            if error:
                return error

        # Validate unique aliases
        return self.validate_aliases()

    def set_initial_tools(self, tools: list[AgentToolResponse]) -> None:
        """Pre-populate with existing tool configurations.

        Args:
            tools: List of existing tool configurations to load
        """
        # Sort by tool_order
        sorted_tools = sorted(tools, key=lambda t: t.tool_order)

        for tool in sorted_tools:
            self._add_tool_editor_with_data(tool)

    def _add_tool_editor_with_data(self, tool: AgentToolResponse) -> None:
        """Add a tool editor and populate it with existing data."""
        tools_list = self.query_one("#tools-list", VerticalScroll)
        editor = AgentToolEditor(
            client=self._client,
            tool_order=self._editor_count,
            id=f"tool-editor-{self._editor_count}",
        )
        tools_list.mount(editor)
        self._editor_count += 1
        self._update_empty_message()

        # Populate after mounting
        editor.populate_from_response(tool)

    def clear(self) -> None:
        """Remove all tool editors."""
        tools_list = self.query_one("#tools-list", VerticalScroll)
        for editor in list(tools_list.query(AgentToolEditor)):
            editor.remove()
        self._editor_count = 0
        self._update_empty_message()
