from collections.abc import Callable
from typing import Any

import pytest
from cognite.client.data_classes.data_modeling import DataModelId
from cognite.client.testing import CogniteClientMock

from cog_mcp.config import Config
from cog_mcp.tools import register_tools


class FakeMCP:
    """Minimal MCP test double that records registered handlers."""

    def __init__(self) -> None:
        self.tools: dict[str, Callable[..., Any]] = {}
        self.resources: dict[str, Callable[..., Any]] = {}

    def tool(self, name: str | None = None) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
        def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
            self.tools[name or func.__name__] = func
            return func

        return decorator

    def resource(self, uri: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
        def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
            self.resources[uri] = func
            return func

        return decorator


class Dumpable:
    """Simple helper for SDK-like objects exposing .dump()."""

    def __init__(self, payload: Any, **attrs: Any) -> None:
        self._payload = payload
        for name, value in attrs.items():
            setattr(self, name, value)

    def dump(self, camel_case: bool = True) -> Any:  # noqa: ARG002 - mirrors SDK signature
        return self._payload


@pytest.fixture
def sample_config() -> Config:
    return Config(
        client_id="client-id",
        tenant_id="tenant-id",
        cluster="westeurope-1",
        project="project-name",
        client_secret="secret",
        data_models=[DataModelId(space="model-space", external_id="Model", version="1")],
        instance_spaces=["space-a", "space-b"],
        token_url=None,
    )


@pytest.fixture
def fake_mcp() -> FakeMCP:
    return FakeMCP()


@pytest.fixture
def cognite_client_mock() -> CogniteClientMock:
    return CogniteClientMock()


@pytest.fixture
def dumpable_factory() -> Callable[..., Dumpable]:
    def _make(payload: Any, **attrs: Any) -> Dumpable:
        return Dumpable(payload, **attrs)

    return _make


@pytest.fixture
def tools(
    fake_mcp: FakeMCP, cognite_client_mock: CogniteClientMock, sample_config: Config
) -> dict[str, Callable[..., Any]]:
    register_tools(fake_mcp, cognite_client_mock, sample_config)
    return fake_mcp.tools
