"""Tests for CI drift detection script."""

from __future__ import annotations

import pytest

from mcpgateway_sdk.resources.auth import AuthResource
from mcpgateway_sdk.resources.cache import CacheResource
from mcpgateway_sdk.resources.sandboxes import SandboxesResource
from mcpgateway_sdk.resources.servers import ServersResource
from mcpgateway_sdk.resources.sessions import SessionsResource
from mcpgateway_sdk.resources.skills import SkillsResource
from mcpgateway_sdk.resources.tools import ToolsResource

RESOURCES = {
    "servers": ServersResource,
    "tools": ToolsResource,
    "skills": SkillsResource,
    "sessions": SessionsResource,
    "sandboxes": SandboxesResource,
    "auth": AuthResource,
    "cache": CacheResource,
}

EXPECTED_TOTAL = 77  # 30 + 3 + 13 + 8 + 16 + 5 + 2


class TestEndpointsAttribute:
    """Each resource has a _endpoints class attribute."""

    @pytest.mark.parametrize("name,cls", list(RESOURCES.items()))
    def test_resource_has_endpoints(self, name: str, cls: type) -> None:
        assert hasattr(cls, "_endpoints"), f"{name} missing _endpoints"

    @pytest.mark.parametrize("name,cls", list(RESOURCES.items()))
    def test_endpoints_is_dict(self, name: str, cls: type) -> None:
        assert isinstance(cls._endpoints, dict), f"{name}._endpoints should be dict"


class TestEndpointFormat:
    """All endpoints have valid (METHOD, path) tuples."""

    VALID_METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE"}

    @pytest.mark.parametrize("name,cls", list(RESOURCES.items()))
    def test_all_endpoints_have_valid_http_method(self, name: str, cls: type) -> None:
        for method_name, (http_method, path) in cls._endpoints.items():
            assert http_method in self.VALID_METHODS, (
                f"{name}.{method_name}: invalid HTTP method '{http_method}'"
            )

    @pytest.mark.parametrize("name,cls", list(RESOURCES.items()))
    def test_all_endpoints_paths_start_with_slash(self, name: str, cls: type) -> None:
        for method_name, (http_method, path) in cls._endpoints.items():
            assert path.startswith("/"), (
                f"{name}.{method_name}: path must start with / (got '{path}')"
            )

    @pytest.mark.parametrize("name,cls", list(RESOURCES.items()))
    def test_all_endpoint_tuples_have_two_elements(self, name: str, cls: type) -> None:
        for method_name, value in cls._endpoints.items():
            assert len(value) == 2, (
                f"{name}.{method_name}: expected 2-tuple, got {len(value)} elements"
            )


class TestEndpointCounts:
    """Total endpoint count matches the expected number."""

    def test_servers_has_30_endpoints(self) -> None:
        assert len(ServersResource._endpoints) == 30

    def test_tools_has_3_endpoints(self) -> None:
        assert len(ToolsResource._endpoints) == 3

    def test_skills_has_13_endpoints(self) -> None:
        assert len(SkillsResource._endpoints) == 13

    def test_sandboxes_has_16_endpoints(self) -> None:
        assert len(SandboxesResource._endpoints) == 16

    def test_auth_has_5_endpoints(self) -> None:
        assert len(AuthResource._endpoints) == 5

    def test_sessions_has_8_endpoints(self) -> None:
        assert len(SessionsResource._endpoints) == 8

    def test_cache_has_2_endpoints(self) -> None:
        assert len(CacheResource._endpoints) == 2

    def test_total_endpoints_matches_expected(self) -> None:
        total = sum(len(cls._endpoints) for cls in RESOURCES.values())
        assert total == EXPECTED_TOTAL, f"Expected {EXPECTED_TOTAL} endpoints, got {total}"


class TestDriftScript:
    """The drift detection script runs successfully."""

    def test_script_returns_zero_on_success(self) -> None:
        from mcpgateway_sdk.scripts.check_sdk_drift import main

        assert main() == 0

    def test_expected_total_matches_script(self) -> None:
        from mcpgateway_sdk.scripts.check_sdk_drift import EXPECTED_TOTAL as SCRIPT_EXPECTED

        assert SCRIPT_EXPECTED == EXPECTED_TOTAL
