from __future__ import annotations

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from src.api.v1 import agents
from src.api.v1.agents import router
from src.services import ai_agent_log_controlled_writeback_dispatch as dispatch_module
from src.services.ai_agent_log_controlled_writeback_dispatch import (
    build_ai_agent_log_controlled_writeback_dispatch_receipt,
    dispatch_latest_ai_agent_log_controlled_writeback,
)


class _FakeResult:
    def __init__(self, value: str | None):
        self.value = value

    def scalar(self) -> str | None:
        return self.value


class _FakeDb:
    def __init__(self):
        self.params: list[dict] = []

    async def execute(self, statement, params: dict):
        self.params.append(params)
        if "fallback_operation_type" in params:
            return _FakeResult("km_linked")
        if "input" in params:
            return _FakeResult(f"op-{params['dispatch_receipt_id'].rsplit('::', 1)[-1]}")
        assert "pg_get_constraintdef" not in str(statement)
        return _FakeResult("existing-op")


class _FakeContext:
    def __init__(self, db: _FakeDb):
        self.db = db

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

    async def __aexit__(self, _exc_type, _exc, _tb) -> bool:
        return False


def test_log_controlled_writeback_dispatch_builder_creates_metadata_receipts():
    payload = build_ai_agent_log_controlled_writeback_dispatch_receipt()
    expected_runtime_sample_count = 3
    expected_target_count = 6
    expected_selector_count = expected_runtime_sample_count * expected_target_count

    assert payload["schema_version"] == "ai_agent_log_controlled_writeback_dispatch_receipt_v1"
    assert payload["status"] == "controlled_writeback_dispatch_ready"
    assert payload["active_blockers"] == []
    assert payload["readback"]["operation_type"] == "log_controlled_writeback_dispatched"
    assert payload["rollups"]["dispatch_batch_count"] == expected_target_count
    assert payload["rollups"]["ready_dispatch_batch_count"] == expected_target_count
    assert payload["rollups"]["target_selector_count"] == expected_selector_count
    assert payload["rollups"]["source_of_truth_diff_count"] == expected_selector_count
    assert payload["rollups"]["post_apply_verifier_ref_count"] == expected_selector_count
    assert payload["rollups"]["runtime_dispatch_performed"] is False

    targets = {batch["target"] for batch in payload["dispatch_batches"]}
    assert targets == {"km", "rag", "playbook", "mcp", "verifier", "ai_agent"}
    for batch in payload["dispatch_batches"]:
        assert batch["status"] == "ready_for_ledger_write"
        assert batch["executor_route"] == "ai_agent_metadata_writeback_executor"
        assert batch["raw_payload_included"] is False
        assert batch["check_mode_verified"] is True
        assert batch["rollback_ready"] is True

    boundaries = payload["operation_boundaries"]
    assert boundaries["metadata_ledger_write_only"] is True
    assert boundaries["executor_dispatch_performed"] is False
    assert boundaries["km_write_performed"] is False
    assert boundaries["rag_index_write_performed"] is False
    assert boundaries["playbook_trust_write_performed"] is False
    assert boundaries["mcp_tool_call_performed"] is False
    assert boundaries["telegram_send_performed"] is False
    assert boundaries["raw_log_payload_persisted"] is False
    assert boundaries["secret_value_collection_allowed"] is False
    assert boundaries["github_api_used"] is False


@pytest.mark.asyncio
async def test_log_controlled_writeback_dispatch_writes_idempotent_ledger_rows(monkeypatch):
    fake_db = _FakeDb()
    monkeypatch.setattr(
        dispatch_module,
        "get_db_context",
        lambda project_id: _FakeContext(fake_db),
    )

    payload = await dispatch_latest_ai_agent_log_controlled_writeback(project_id="awoooi")

    assert payload["status"] == "controlled_writeback_dispatch_ready"
    assert payload["rollups"]["runtime_dispatch_performed"] is True
    assert payload["rollups"]["dispatch_ledger_row_count"] == 6
    assert payload["rollups"]["inserted_dispatch_ledger_row_count"] == 6
    assert payload["operation_boundaries"]["executor_dispatch_performed"] is True
    write_params = [params for params in fake_db.params if "input" in params]
    assert len(write_params) == 6
    assert payload["dispatch_result"]["operation_type"] == "log_controlled_writeback_dispatched"
    assert payload["dispatch_result"]["ledger_operation_type"] == "km_linked"
    assert payload["dispatch_result"]["semantic_operation_type"] == (
        "log_controlled_writeback_dispatched"
    )

    for params in write_params:
        assert params["operation_type"] == "log_controlled_writeback_dispatched"
        assert params["ledger_operation_type"] == "km_linked"
        assert params["actor"] == "ai_agent_metadata_writeback_executor"
        assert "dispatch_receipt_id" in params
        assert '"semantic_operation_type": "log_controlled_writeback_dispatched"' in params["input"]
        assert '"ledger_operation_type": "km_linked"' in params["input"]
        assert "raw_payload_included" in params["input"]
        assert "False" not in params["input"]
        assert "telegram_send_performed" in params["output"]


def test_log_controlled_writeback_dispatch_endpoint_returns_receipt(monkeypatch):
    async def fake_dispatch():
        payload = build_ai_agent_log_controlled_writeback_dispatch_receipt()
        payload["rollups"]["runtime_dispatch_performed"] = True
        return payload

    monkeypatch.setattr(
        agents,
        "dispatch_latest_ai_agent_log_controlled_writeback",
        fake_dispatch,
    )
    app = FastAPI()
    app.include_router(router, prefix="/api/v1")
    client = TestClient(app)

    response = client.post("/api/v1/agents/agent-log-controlled-writeback-dispatch")

    assert response.status_code == 200
    payload = response.json()
    assert payload["schema_version"] == "ai_agent_log_controlled_writeback_dispatch_receipt_v1"
    assert payload["status"] == "controlled_writeback_dispatch_ready"
    assert payload["rollups"]["runtime_dispatch_performed"] is True
