from __future__ import annotations

from typing import Any

DEFAULT_ALLOWED_TOOLS = (
    "read_file",
    "search_text",
    "propose_patch",
    "run_command",
    "web_search",
)
ALL_KNOWN_TOOLS = (
    "read_file",
    "search_text",
    "propose_patch",
    "semantic_search",
    "run_command",
    "web_search",
)

_TOOL_DEFINITIONS: dict[str, dict[str, Any]] = {
    "read_file": {
        "type": "function",
        "function": {
            "name": "read_file",
            "description": "Read a workspace-relative file (max 64KB returned).",
            "parameters": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Workspace-relative file path.",
                    }
                },
                "required": ["path"],
                "additionalProperties": False,
            },
        },
    },
    "search_text": {
        "type": "function",
        "function": {
            "name": "search_text",
            "description": (
                "Search workspace files with a case-insensitive substring pattern. "
                "Use a directory path for scope (e.g. app/api/routes), not a single file."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "pattern": {
                        "type": "string",
                        "description": "Text pattern to search for (case-insensitive substring).",
                    },
                    "path": {
                        "type": "string",
                        "description": (
                            "Optional workspace-relative directory to scope the search "
                            "(e.g. app, app/api/routes, src/routes). Omit to search the whole workspace."
                        ),
                    },
                },
                "required": ["pattern"],
                "additionalProperties": False,
            },
        },
    },
    "propose_patch": {
        "type": "function",
        "function": {
            "name": "propose_patch",
            "description": (
                "Propose file changes for user review. REQUIRED for any create/add/edit/implement "
                "request — files are not written until propose_patch is called and the user accepts. "
                "Never substitute chat-only code blocks for this tool. "
                "Prefer a small unique old_text snippet that appears once in the file (not the entire "
                "file). new_text replaces that exact snippet. For brand-new files, omit/empty old_text "
                "and set full new_text — never invent old_text for a create. Do not overwrite README "
                "when the user asked for a different new file."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "summary": {
                        "type": "string",
                        "description": "Short summary of the proposed change.",
                    },
                    "file_changes": {
                        "type": "array",
                        "description": "List of file edits to propose.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "path": {"type": "string"},
                                "old_text": {
                                    "type": "string",
                                    "description": (
                                        "Exact text to find for updates. Prefer a short unique "
                                        "contiguous snippet from read_file, not a rewritten whole "
                                        "file. For NEW files leave this empty/omitted."
                                    ),
                                },
                                "new_text": {
                                    "type": "string",
                                    "description": (
                                        "Replacement for old_text. For new files, the full file "
                                        "contents."
                                    ),
                                },
                            },
                            "required": ["path"],
                            "additionalProperties": False,
                        },
                    },
                },
                "required": ["file_changes"],
                "additionalProperties": False,
            },
        },
    },
    "semantic_search": {
        "type": "function",
        "function": {
            "name": "semantic_search",
            "description": "Semantic search over indexed repository content.",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Natural language search query.",
                    },
                    "top_k": {
                        "type": "integer",
                        "description": "Maximum number of hits to return.",
                    },
                    "paths": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Optional path filters.",
                    },
                },
                "required": ["query"],
                "additionalProperties": False,
            },
        },
    },
    "run_command": {
        "type": "function",
        "function": {
            "name": "run_command",
            "description": "Run a command in the local workspace after user approval.",
            "parameters": {
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "Command to run.",
                    },
                    "cwd": {
                        "type": "string",
                        "description": "Optional workspace-relative working directory.",
                    },
                    "timeout_seconds": {
                        "type": "integer",
                        "description": "Optional command timeout in seconds.",
                    },
                },
                "required": ["command"],
                "additionalProperties": False,
            },
        },
    },
    "web_search": {
        "type": "function",
        "function": {
            "name": "web_search",
            "description": (
                "Search the public web for general knowledge, definitions, docs, and "
                "up-to-date facts. Executed by the Lucos cloud (not the local daemon). "
                "Prefer this over workspace search for questions that are not about the "
                "user's local codebase (e.g. \"What is HTML?\")."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Web search query.",
                    },
                    "max_results": {
                        "type": "integer",
                        "description": "Maximum number of results to return (default 5, max 10).",
                    },
                },
                "required": ["query"],
                "additionalProperties": False,
            },
        },
    },
}


def resolve_allowed_tools(
    *,
    agent_allowed_tools: list[str] | None = None,
    skill_allowed_tools: list[str] | None = None,
) -> list[str]:
    for source in (agent_allowed_tools, skill_allowed_tools):
        if not source:
            continue
        if "*" in source:
            return list(ALL_KNOWN_TOOLS)
        return [tool for tool in source if tool in _TOOL_DEFINITIONS]
    return list(DEFAULT_ALLOWED_TOOLS)


def build_openai_tools(allowed_tools: list[str]) -> list[dict[str, Any]]:
    return [_TOOL_DEFINITIONS[name] for name in allowed_tools if name in _TOOL_DEFINITIONS]
