from __future__ import annotations

import uuid
from types import SimpleNamespace

import pytest

from src.plugins.mcp import gateway as gateway_module
from src.plugins.mcp.gateway import GateCheckResult, GatewayContext, McpGateway
from src.plugins.mcp.interfaces import MCPTool, MCPToolProvider, MCPToolResult


class FakeDb:
    def __init__(self) -> None:
        self.added: list[object] = []
        self.flush_count = 0

    def add(self, item: object) -> None:
        self.added.append(item)

    async def flush(self) -> None:
        self.flush_count += 1


@pytest.mark.asyncio
async def test_write_audit_persists_blocked_gate_without_tool_row() -> None:
    db = FakeDb()
    run_id = uuid.uuid4()

    await McpGateway(db)._write_audit(
        ctx=GatewayContext(
            project_id="awoooi",
            agent_id="openclaw-sre",
            tool_name="missing_tool",
            run_id=run_id,
            trace_id="trace-audit-gap",
        ),
        tool_row=None,
        parameters={"namespace": "awoooi-prod"},
        result=None,
        gate_result=GateCheckResult(),
        result_status="blocked",
        block_gate=1,
        block_reason="E-MCP-GATE-001: project blocked",
        latency_ms=12,
    )

    assert db.flush_count == 1
    assert len(db.added) == 1
    audit = db.added[0]
    assert audit.project_id == "awoooi"
    assert audit.run_id == run_id
    assert audit.tool_id is None
    assert audit.tool_name == "missing_tool"
    assert audit.result_status == "blocked"
    assert audit.block_gate == 1
    assert audit.gate_result["schema_version"] == "awooop_mcp_gateway_audit_v1"
    assert audit.gate_result["gateway_path"] == "awooop_mcp_gateway"
    assert audit.gate_result["policy_enforced"] is True


class FakeProvider(MCPToolProvider):
    def __init__(self) -> None:
        self.calls: list[tuple[str, dict]] = []

    @property
    def name(self) -> str:
        return "kubernetes"

    async def list_tools(self) -> list[MCPTool]:
        return [MCPTool(name="kubectl_get", description="", input_schema={})]

    async def execute(self, tool_name: str, parameters: dict) -> MCPToolResult:
        self.calls.append((tool_name, parameters))
        return MCPToolResult(success=True, execution_id="provider-ok", output={"ok": True})


class FakeProviderRegistry:
    def __init__(self, provider: FakeProvider) -> None:
        self.provider = provider

    def get(self, _name: str):
        return None

    def all(self) -> list[FakeProvider]:
        return [self.provider]


@pytest.mark.asyncio
async def test_execute_tool_resolves_provider_by_tool_manifest(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    provider = FakeProvider()
    monkeypatch.setattr(
        gateway_module,
        "get_provider_registry",
        lambda: FakeProviderRegistry(provider),
    )

    result = await McpGateway(FakeDb())._execute_tool(
        GatewayContext(
            project_id="awoooi",
            agent_id="pre_decision_investigator",
            tool_name="kubectl_get",
            trace_id="INC-GW",
        ),
        SimpleNamespace(tool_name="kubectl_get"),
        {
            "namespace": "awoooi-prod",
            "_mcp_audit": {
                "incident_id": "INC-GW",
                "session_id": "incident:INC-GW:pre_decision",
                "flywheel_node": "sense",
                "agent_role": "pre_decision_investigator",
            },
        },
    )

    assert result.success is True
    assert provider.calls
    tool_name, parameters = provider.calls[0]
    assert tool_name == "kubectl_get"
    assert parameters["_mcp_audit"]["gateway_path"] == "awooop_mcp_gateway"
    assert parameters["_mcp_audit"]["incident_id"] == "INC-GW"
    assert parameters["_mcp_audit"]["flywheel_node"] == "sense"
