"""Tool definitions in OpenAI format and dispatch table."""

from __future__ import annotations

from typing import Any, Awaitable, Callable

# Dispatch table: tool_name -> async callable
_DISPATCH: dict[str, Callable[..., Awaitable[str]]] = {}


def register(name: str, func: Callable[..., Awaitable[str]]) -> None:
    """Register a tool implementation."""
    _DISPATCH[name] = func


async def dispatch(tool_name: str, arguments: dict[str, Any]) -> str:
    """Execute a tool by name. Returns result string or error."""
    func = _DISPATCH.get(tool_name)
    if not func:
        return f"Error: Unknown tool '{tool_name}'"
    try:
        return await func(**arguments)
    except Exception as e:
        return f"Error executing {tool_name}: {type(e).__name__}: {e}"


# ---------------------------------------------------------------------------
# Tool definitions in OpenAI function-calling format
# ---------------------------------------------------------------------------

TOOL_DEFINITIONS: list[dict[str, Any]] = [
    # --- Local tools ---
    {
        "type": "function",
        "function": {
            "name": "run_command",
            "description": (
                "Execute a shell command on this server. "
                "Returns exit_code, stdout, and stderr. "
                "Use for: checking service status, reading logs, restarting services, "
                "running openclaw CLI commands, installing packages."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "The shell command to execute",
                    },
                    "cwd": {
                        "type": "string",
                        "description": "Working directory (default: $HOME)",
                    },
                },
                "required": ["command"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": (
                "Read a file's contents. No path restrictions. "
                "Use for: reading config files, logs, source code."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Absolute path to the file",
                    },
                },
                "required": ["path"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": (
                "Write content to a file. Automatically creates a .bak backup. "
                "Restricted to OpenClaw-related paths (~/.openclaw, /opt/openclaw, etc)."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Absolute path to the file",
                    },
                    "content": {
                        "type": "string",
                        "description": "Content to write",
                    },
                },
                "required": ["path", "content"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "edit_file",
            "description": (
                "Find and replace text in a file. Creates .bak backup. "
                "Restricted to OpenClaw-related paths."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Absolute path to the file",
                    },
                    "old_text": {
                        "type": "string",
                        "description": "Text to find (exact match)",
                    },
                    "new_text": {
                        "type": "string",
                        "description": "Replacement text",
                    },
                },
                "required": ["path", "old_text", "new_text"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "list_directory",
            "description": "List directory contents with type indicators (d=dir, f=file).",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Directory path (default: home directory)",
                    },
                },
                "required": [],
            },
        },
    },
    # --- Confirmation tool ---
    {
        "type": "function",
        "function": {
            "name": "ask_user",
            "description": (
                "Ask the user for confirmation before performing a risky operation. "
                "You MUST call this before: changing OpenClaw config (openclaw config set), "
                "restarting services (systemctl restart), writing or editing files, "
                "opening firewall ports (ufw allow), or any action that modifies the system. "
                "Describe what you plan to do and why. The user will approve or deny. "
                "Do NOT proceed with the action if denied."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "question": {
                        "type": "string",
                        "description": (
                            "Clear description of what you want to do and why. "
                            "Example: 'I want to set gateway.bind to lan using "
                            "`openclaw config set gateway.bind lan` so the UI is "
                            "accessible on your local network. OK to proceed?'"
                        ),
                    },
                },
                "required": ["question"],
            },
        },
    },
    # --- MCP tools (remote knowledge base) ---
    {
        "type": "function",
        "function": {
            "name": "mcp_search_knowledge",
            "description": (
                "Search the EasyClaw knowledge base (17+ OpenClaw guides). "
                "Use for general questions about OpenClaw setup, configuration, features."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_get_full_guide",
            "description": "Get a complete guide by topic (e.g. 'installation', 'skills', 'channels').",
            "parameters": {
                "type": "object",
                "properties": {
                    "topic": {
                        "type": "string",
                        "description": "Guide topic",
                    },
                },
                "required": ["topic"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_get_model_recommendation",
            "description": "Get LLM model recommendations for a specific use case.",
            "parameters": {
                "type": "object",
                "properties": {
                    "use_case": {
                        "type": "string",
                        "description": "What the model will be used for",
                    },
                },
                "required": ["use_case"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_validate_config",
            "description": "Validate the current OpenClaw configuration against best practices.",
            "parameters": {"type": "object", "properties": {}, "required": []},
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_recommend_skills",
            "description": "Get skill recommendations for a use case.",
            "parameters": {
                "type": "object",
                "properties": {
                    "use_case": {
                        "type": "string",
                        "description": "What skills are needed for",
                    },
                },
                "required": ["use_case"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_security_audit",
            "description": "Run a security audit checklist for the OpenClaw deployment.",
            "parameters": {"type": "object", "properties": {}, "required": []},
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_estimate_cost",
            "description": "Estimate monthly costs for running OpenClaw with a given model.",
            "parameters": {
                "type": "object",
                "properties": {
                    "model": {
                        "type": "string",
                        "description": "Model name (default: minimax-m2.5)",
                    },
                    "daily_messages": {
                        "type": "integer",
                        "description": "Expected daily messages (default: 100)",
                    },
                },
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_generate_config",
            "description": "Generate an OpenClaw config file for a given use case template.",
            "parameters": {
                "type": "object",
                "properties": {
                    "template": {
                        "type": "string",
                        "description": "Template name (default: 'default')",
                    },
                },
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_search_web",
            "description": "Search the web via SearXNG for current information.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Search query",
                    },
                    "engines": {
                        "type": "string",
                        "description": "Search engines to use (default: 'google')",
                    },
                },
                "required": ["query"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_diagnose_issue",
            "description": (
                "Diagnose an OpenClaw error using the knowledge base. "
                "Provide the error text and optional context."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "error_text": {
                        "type": "string",
                        "description": "The error message or log output",
                    },
                    "context": {
                        "type": "string",
                        "description": "Context: 'gateway', 'config', 'install', 'general'",
                    },
                },
                "required": ["error_text"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_validate_deployment",
            "description": "Run a full deployment health checklist.",
            "parameters": {
                "type": "object",
                "properties": {
                    "os_type": {
                        "type": "string",
                        "description": "OS type (default: 'linux')",
                    },
                },
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_get_foreman_config",
            "description": "Generate a full Agent Johnny 5 configuration.",
            "parameters": {
                "type": "object",
                "properties": {
                    "model": {"type": "string", "description": "Model name"},
                    "channel": {"type": "string", "description": "Channel type"},
                    "bind": {"type": "string", "description": "Bind mode"},
                },
                "required": [],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "mcp_troubleshoot_gateway",
            "description": (
                "Troubleshoot OpenClaw gateway issues. "
                "Provide symptom like '421 error', 'not starting', 'timeout'."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "symptom": {
                        "type": "string",
                        "description": "Description of the gateway issue",
                    },
                },
                "required": [],
            },
        },
    },
]


def get_tool_definitions(include_mcp: bool = True) -> list[dict[str, Any]]:
    """Return tool definitions, optionally excluding MCP tools."""
    if include_mcp:
        return TOOL_DEFINITIONS
    return [
        t
        for t in TOOL_DEFINITIONS
        if not t["function"]["name"].startswith("mcp_")
    ]
