"""
Unit tests for orchestration.catalog_builder.

Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

from mcp_proxy_adapter.core.orchestration.catalog_builder import (
    ServerInput,
    build_catalog_and_tool_context,
)


class TestBuildCatalogAndToolContext:
    """Tests for build_catalog_and_tool_context."""

    def test_empty_servers_version_one(self):
        """Empty filtered list yields version 1 and empty catalog/tool context."""
        catalog, tool_ctx = build_catalog_and_tool_context([])
        assert catalog.version == 1
        assert tool_ctx.get_version() == 1
        assert len(catalog.get_servers()) == 0
        assert len(tool_ctx.get_tools()) == 0

    def test_empty_servers_with_previous_version(self):
        """With previous_version, empty list still yields next version."""
        catalog, tool_ctx = build_catalog_and_tool_context([], previous_version=5)
        assert catalog.version == 6
        assert tool_ctx.get_version() == 6

    def test_one_server_one_command(self):
        """One server with one command produces catalog and tool context."""
        servers: list[ServerInput] = [
            {
                "server_id": "s1",
                "host": "localhost",
                "port": 8080,
                "commands": [
                    {
                        "name": "echo",
                        "schema": {
                            "type": "object",
                            "properties": {"message": {"type": "string"}},
                        },
                        "metadata": {"summary": "Echo message"},
                    },
                ],
            },
        ]
        catalog, tool_ctx = build_catalog_and_tool_context(servers)
        assert catalog.version == 1
        assert tool_ctx.get_version() == 1
        assert len(catalog.get_servers()) == 1
        s = catalog.get_server("s1")
        assert s is not None
        assert s.server_id == "s1"
        assert s.host == "localhost"
        assert s.port == 8080
        cmd = catalog.get_command("s1", "echo")
        assert cmd is not None
        assert cmd.command_name == "echo"
        assert cmd.summary == "Echo message"
        assert "message" in cmd.parameter_definitions
        assert len(tool_ctx.get_tools()) == 1
        tool = tool_ctx.get_tool("s1", "echo")
        assert tool is not None
        assert tool.command_name == "echo"
        assert tool.server_id == "s1"

    def test_required_parameters_from_graph(self):
        """Required parameters are derived from parameter graph (FR-4)."""
        servers: list[ServerInput] = [
            {
                "server_id": "s1",
                "host": "h",
                "port": 80,
                "commands": [
                    {
                        "name": "cmd",
                        "schema": {
                            "properties": {
                                "a": {},
                                "b": {"dependsOn": ["a"]},
                            },
                            "required": ["b"],
                        },
                    },
                ],
            },
        ]
        catalog, _ = build_catalog_and_tool_context(servers)
        cmd = catalog.get_command("s1", "cmd")
        assert cmd is not None
        assert set(cmd.required_parameters) == {"a", "b"}

    def test_version_monotonic(self):
        """Version increments from previous_version."""
        servers: list[ServerInput] = [
            {"server_id": "s1", "host": "h", "port": 1, "commands": []},
        ]
        c1, t1 = build_catalog_and_tool_context(servers, previous_version=10)
        assert c1.version == 11
        assert t1.get_version() == 11
        c2, t2 = build_catalog_and_tool_context(servers, previous_version=11)
        assert c2.version == 12
        assert t2.get_version() == 12

    def test_skips_invalid_server_entries(self):
        """Servers missing server_id, host, or port are skipped."""
        servers: list[ServerInput] = [
            {"server_id": "s1", "host": "h", "port": 80, "commands": []},
            {"host": "h2", "port": 81, "commands": []},
            {"server_id": "s3", "port": 82, "commands": []},
            {"server_id": "s4", "host": "h4", "commands": []},
        ]
        catalog, _ = build_catalog_and_tool_context(servers)
        assert list(catalog.get_servers().keys()) == ["s1"]

    def test_skips_commands_without_name_or_schema(self):
        """Commands without name or schema are skipped."""
        servers: list[ServerInput] = [
            {
                "server_id": "s1",
                "host": "h",
                "port": 80,
                "commands": [
                    {"name": "ok", "schema": {"properties": {}}},
                    {"schema": {"properties": {}}},
                    {"name": "no_schema"},
                    {"name": "also_ok", "schema": {"properties": {"x": {}}}},
                ],
            },
        ]
        catalog, tool_ctx = build_catalog_and_tool_context(servers)
        cmds = catalog.get_commands("s1")
        assert set(cmds.keys()) == {"ok", "also_ok"}
        assert len(tool_ctx.get_tools()) == 2

    def test_two_servers_multiple_commands(self):
        """Multiple servers and commands are all present and version-aligned."""
        servers: list[ServerInput] = [
            {
                "server_id": "s1",
                "host": "h1",
                "port": 80,
                "commands": [
                    {"name": "a", "schema": {"properties": {}}},
                    {"name": "b", "schema": {"properties": {"p": {}}}},
                ],
            },
            {
                "server_id": "s2",
                "host": "h2",
                "port": 81,
                "commands": [
                    {"name": "x", "schema": {"properties": {}, "required": []}},
                ],
            },
        ]
        catalog, tool_ctx = build_catalog_and_tool_context(servers)
        assert catalog.version == tool_ctx.get_version()
        assert len(catalog.get_servers()) == 2
        assert len(catalog.get_commands("s1")) == 2
        assert len(catalog.get_commands("s2")) == 1
        assert len(tool_ctx.get_tools()) == 3
        assert len(tool_ctx.get_tools_by_server("s1")) == 2
        assert len(tool_ctx.get_tools_by_server("s2")) == 1
