"""
Tool routing: local IndexedDB reads with official Linear MCP fallback/writes.
"""

from __future__ import annotations

from typing import Any

from . import local_handlers
from .official_session import OfficialMcpSessionManager
from .reader import LinearLocalReader

class ToolRouter:
    """Routes read calls through local cache first, falling back to official MCP."""

    def __init__(
        self,
        reader: LinearLocalReader,
        official: OfficialMcpSessionManager,
    ):
        self._reader = reader
        self._official = official

    def _call_local(
        self,
        tool_name: str,
        arguments: dict[str, Any],
    ) -> Any:
        handler = local_handlers.LOCAL_READ_HANDLERS.get(tool_name)
        if handler is None:
            raise local_handlers.LocalFallbackRequested(
                "unsupported_tool", f"tool '{tool_name}' not implemented in local cache"
            )
        return handler(self._reader, **arguments)

    def call_official(self, tool_name: str, arguments: dict[str, Any] | None = None) -> Any:
        """Call official MCP directly (used for writes and explicit fallback)."""
        return self._official.call_tool(tool_name, arguments or {})

    def call_read(self, tool_name: str, arguments: dict[str, Any] | None = None) -> Any:
        """Read with local-first strategy: refresh cache, try local, fallback to official."""
        args = arguments or {}
        try:
            self._reader.refresh_cache()
        except Exception:
            # If local refresh itself fails unexpectedly, preserve read availability
            # by falling back to official MCP.
            return self.call_official(tool_name, args)

        try:
            return self._call_local(tool_name, args)
        except local_handlers.LocalFallbackRequested:
            return self.call_official(tool_name, args)
