from __future__ import annotations

from typing import Any

import pytest

from src.services import mcp_audit_service


class _FakeDb:
    def __init__(self) -> None:
        self.executed_params: list[dict[str, Any]] = []
        self.statements: list[str] = []

    async def execute(self, _statement: Any, params: dict[str, Any]) -> None:
        self.statements.append(str(_statement))
        self.executed_params.append(params)


class _FakeDbContext:
    def __init__(self, db: _FakeDb) -> None:
        self.db = db

    async def __aenter__(self) -> _FakeDb:
        return self.db

    async def __aexit__(self, *_args: Any) -> None:
        return None


@pytest.mark.asyncio
async def test_record_mcp_call_normalizes_long_session_id(monkeypatch) -> None:
    db = _FakeDb()
    monkeypatch.setattr(
        mcp_audit_service,
        "get_db_context",
        lambda _project_id=None: _FakeDbContext(db),
    )

    await mcp_audit_service.record_mcp_call(
        mcp_server="k8s_provider",
        tool_name="get_pods",
        input_params={
            "_mcp_audit": {
                "session_id": "incident:INC-20260505-E8033A:pre_decision",
                "agent_role": "pre_decision_investigator",
            },
        },
        output_result={"ok": True},
        duration_ms=12,
        success=True,
        error_message=None,
    )

    audit_insert_params = db.executed_params[0]
    assert audit_insert_params["session_id"] == "inc:INC-20260505-E8033A:pre"
    assert len(audit_insert_params["session_id"]) <= 36


@pytest.mark.asyncio
async def test_record_mcp_call_bridges_legacy_direct_path_to_awooop_audit(monkeypatch) -> None:
    db = _FakeDb()
    monkeypatch.setattr(
        mcp_audit_service,
        "get_db_context",
        lambda _project_id=None: _FakeDbContext(db),
    )

    await mcp_audit_service.record_mcp_call(
        mcp_server="ssh_host",
        tool_name="ssh_get_docker_logs",
        input_params={
            "_mcp_audit": {
                "session_id": "incident:INC-20260512-B6C589:pre_decision",
                "incident_id": "INC-20260512-B6C589",
                "agent_role": "pre_decision_investigator",
                "gateway_path": "legacy_direct_provider",
            },
            "project_id": "awoooi",
            "secret": "must-not-leak",
        },
        output_result={"ok": True},
        duration_ms=37,
        success=True,
        error_message=None,
    )

    bridge_params = db.executed_params[2]
    assert "INSERT INTO awooop_mcp_gateway_audit" in db.statements[2]
    assert bridge_params["project_id"] == "awoooi"
    assert bridge_params["run_id"] is None
    assert bridge_params["trace_id"] == "INC-20260512-B6C589"
    assert bridge_params["agent_id"] == "pre_decision_investigator"
    assert bridge_params["tool_name"] == "legacy:ssh_host:ssh_get_docker_logs"
    assert bridge_params["result_status"] == "success"
    assert bridge_params["block_reason"] is None
    assert bridge_params["latency_ms"] == 37
    assert "legacy_mcp_bridge_v1" in bridge_params["gate_result"]
    assert "legacy direct provider path; bridge audit only" in bridge_params["gate_result"]


@pytest.mark.asyncio
async def test_record_mcp_call_skips_bridge_for_first_class_awooop_gateway(monkeypatch) -> None:
    db = _FakeDb()
    monkeypatch.setattr(
        mcp_audit_service,
        "get_db_context",
        lambda _project_id=None: _FakeDbContext(db),
    )

    await mcp_audit_service.record_mcp_call(
        mcp_server="kubernetes",
        tool_name="kubectl_get",
        input_params={
            "_mcp_audit": {
                "project_id": "awoooi",
                "run_id": "9d769d02-a036-4c9d-b659-5656c8d1bd5d",
                "agent_id": "openclaw-sre",
                "trace_id": "trace-1",
                "gateway_path": "awooop_mcp_gateway",
            },
        },
        output_result={"items": []},
        duration_ms=18,
        success=True,
        error_message=None,
    )

    assert len(db.executed_params) == 2
    assert all("awooop_mcp_gateway_audit" not in statement for statement in db.statements)
