from __future__ import annotations

import json
from typing import Any, Dict

from .ops_tools import summarize_result
from .repo_context import RepoContext
from .state_store import StateStore


class ToolRouter:
    def __init__(
        self,
        tool_registry: Dict[str, Any],
        repo_context: RepoContext,
        state_store: StateStore,
    ) -> None:
        self.tool_registry = tool_registry
        self.repo_context = repo_context
        self.state_store = state_store
        self.alias_map = {
            "workspace.initialize": "workspace_initialize",
            "tx.event_append": "tx_event_append",
            "tx.state_save": "tx_state_save",
            "tx.state_rebuild": "tx_state_rebuild",
            "session.capture_context": "session_capture_context",
            "repo.verify": "repo_verify",
            "repo.commit": "repo_commit",
            "repo.status_summary": "repo_status_summary",
            "repo.commit_message_suggest": "repo_commit_message_suggest",
            "tests.suggest": "tests_suggest",
            "tests.suggest_from_failures": "tests_suggest_from_failures",
            "ops.compact_context": "ops_compact_context",
            "ops.handoff_export": "ops_handoff_export",
            "ops.resume_brief": "ops_resume_brief",
            "ops.start_task": "ops_start_task",
            "ops.update_task": "ops_update_task",
            "ops.end_task": "ops_end_task",
            "ops.capture_state": "ops_capture_state",
            "ops.task_summary": "ops_task_summary",
            "ops.observability_summary": "ops_observability_summary",
        }

    def tools_list(self) -> Dict[str, Any]:
        tools = []
        for name, spec in self.tool_registry.items():
            input_schema = dict(spec["input_schema"])
            properties = dict(input_schema.get("properties") or {})

            properties["truncate_limit"] = {"type": ["integer", "null"]}
            input_schema["properties"] = properties
            input_schema["required"] = list(input_schema.get("required") or [])
            tools.append(
                {
                    "name": name,
                    "description": spec["description"],
                    "inputSchema": input_schema,
                }
            )
        return {"tools": tools}

    def tools_call(self, name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
        resolved_name = name
        if resolved_name not in self.tool_registry:
            resolved_name = self.alias_map.get(resolved_name, resolved_name)

        if resolved_name not in self.tool_registry:
            raise ValueError(f"Unknown tool: {name}")

        tool_spec = self.tool_registry[resolved_name]
        input_schema = tool_spec.get("input_schema") or {}
        required_fields = list(input_schema.get("required") or [])
        if required_fields:
            if not arguments:
                missing_list = ", ".join(required_fields)
                raise ValueError(f"Missing required argument(s): {missing_list}")
            missing = [
                field
                for field in required_fields
                if field not in arguments or arguments.get(field) is None
            ]
            if missing:
                missing_list = ", ".join(missing)
                raise ValueError(f"Missing required argument(s): {missing_list}")

        truncate_limit = None
        if arguments and "truncate_limit" in arguments:
            raw_limit = arguments.get("truncate_limit")
            if isinstance(raw_limit, int) and raw_limit > 0:
                truncate_limit = raw_limit
            arguments = {k: v for k, v in arguments.items() if k != "truncate_limit"}

        if (
            resolved_name != "workspace_initialize"
            and resolved_name in self.tool_registry
            and resolved_name != "tests_suggest"
            and resolved_name != "tests_suggest_from_failures"
        ):
            if not self.repo_context.has_repo_root():
                raise ValueError(
                    "project root is not initialized; call workspace_initialize(cwd) before using file-backed tools"
                )

        handler = tool_spec["handler"]
        result = handler(**arguments) if arguments else handler()  # type: ignore[misc]

        summary_limit = truncate_limit if truncate_limit is not None else 2000
        result_payload = summarize_result(result, limit=summary_limit)
        if not isinstance(result_payload, dict):
            result_payload = {"result": result_payload}

        content_payload = {
            "content": [
                {
                    "type": "text",
                    "text": json.dumps(result_payload, ensure_ascii=False),
                }
            ]
        }
        return content_payload
