"""Compatibility seams for the extracted ``/v1/runs`` lifecycle."""

import sys
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock

import pytest

from gateway.platforms import api_server
from gateway.platforms import api_server_room_grants
from gateway.platforms import api_server_runs


_HTTP_HANDLER_DELEGATES = (
    ("_handle_get_run", "_handle_get_run"),
    ("_handle_run_events", "_handle_run_events"),
    ("_handle_run_approval", "_handle_run_approval"),
    ("_handle_steer_run", "_handle_steer_run"),
    ("_handle_stop_run", "_handle_stop_run"),
)

_RUN_METHODS = {
    "_set_run_status",
    "_make_run_event_callback",
    "_run_idempotency_scope",
    "_check_run_auth",
    "_durable_run_status",
    "_handle_runs",
    "_request_owns_run",
    *(adapter_name for adapter_name, _ in _HTTP_HANDLER_DELEGATES),
    "_sweep_orphaned_runs",
    "_sweep_orphaned_runs_once",
}


def test_api_server_keeps_run_methods_on_the_adapter_class():
    assert _RUN_METHODS <= api_server.APIServerAdapter.__dict__.keys()


@pytest.mark.asyncio
@pytest.mark.parametrize(("adapter_name", "implementation_name"), _HTTP_HANDLER_DELEGATES)
async def test_run_http_handlers_delegate_without_changing_method_surface(
    monkeypatch, adapter_name, implementation_name
):
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    request = object()
    expected = object()
    implementation = AsyncMock(return_value=expected)
    monkeypatch.setattr(api_server_runs, implementation_name, implementation)

    assert await getattr(adapter, adapter_name)(request) is expected
    implementation.assert_awaited_once_with(
        adapter,
        request,
        _api_server=sys.modules[api_server.__name__],
    )


@pytest.mark.asyncio
async def test_decorated_run_admission_delegates_and_releases_slot(monkeypatch):
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    adapter._room_grant_token = MagicMock(return_value="room-grant")
    adapter._check_run_auth = MagicMock(return_value=None)
    adapter._draining_response = MagicMock(return_value=None)
    adapter._pending_agent_requests = 0
    request = SimpleNamespace(path="/v1/runs")
    expected = object()
    implementation = AsyncMock(return_value=expected)
    monkeypatch.setattr(api_server_runs, "_handle_runs", implementation)

    assert await adapter._handle_runs(request) is expected
    implementation.assert_awaited_once_with(
        adapter,
        request,
        _api_server=sys.modules[api_server.__name__],
    )
    adapter._check_run_auth.assert_called_once_with(request, permission="dispatch")
    assert adapter._pending_agent_requests == 0


def test_run_status_method_delegates(monkeypatch):
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    expected = {"run_id": "run-1", "status": "running"}
    implementation = MagicMock(return_value=expected)
    monkeypatch.setattr(api_server_runs, "_set_run_status", implementation)

    assert adapter._set_run_status("run-1", "running", last_event="run.started") is expected
    implementation.assert_called_once_with(
        adapter,
        "run-1",
        "running",
        last_event="run.started",
    )


def test_room_scoped_run_policy_delegates_with_legacy_api_bindings(monkeypatch):
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    request = object()
    scope = MagicMock(return_value="scope-hash")
    auth = MagicMock(return_value=None)
    monkeypatch.setattr(api_server_runs, "_run_idempotency_scope", scope)
    monkeypatch.setattr(api_server_runs, "_check_run_auth", auth)

    assert adapter._run_idempotency_scope(request) == "scope-hash"
    assert adapter._check_run_auth(request, permission="stop") is None
    scope.assert_called_once_with(
        adapter,
        request,
        _api_server=sys.modules[api_server.__name__],
    )
    auth.assert_called_once_with(
        adapter,
        request,
        permission="stop",
        _api_server=sys.modules[api_server.__name__],
    )


def test_run_state_initialization_and_teardown_are_shard_owned():
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    store = MagicMock()
    store_factory = MagicMock(return_value=store)

    api_server_runs._initialize_run_state(
        adapter,
        store_factory=store_factory,
    )

    store_factory.assert_called_once_with()
    assert adapter._run_idempotency_store is store
    assert adapter._run_idempotency_ids == set()
    assert adapter._run_owners == {}
    assert adapter._run_streams == {}
    assert adapter._run_streams_created == {}
    assert adapter._run_stream_subscribers == set()
    assert adapter._active_run_agents == {}
    assert adapter._active_run_tasks == {}
    assert adapter._stopping_run_ids == set()
    assert adapter._run_statuses == {}
    assert adapter._run_approval_sessions == {}

    api_server_runs._close_run_state(adapter)
    store.close.assert_called_once_with()


def test_run_capability_metadata_is_shard_owned():
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)
    adapter._run_idempotency_store = SimpleNamespace(durable=True)
    store_type = SimpleNamespace(RETENTION_SECONDS=123)

    assert api_server_runs._idempotency_capabilities(
        adapter,
        store_type=store_type,
    ) == {
        "supported": True,
        "durable": True,
        "retention_seconds": 123,
    }


def test_roomlink_and_run_route_tuples_are_shard_owned():
    adapter = api_server.APIServerAdapter.__new__(api_server.APIServerAdapter)

    room_routes = api_server_room_grants._http_routes(adapter)
    run_routes = api_server_runs._http_routes(adapter)

    assert [(method, path) for method, path, _ in room_routes] == [
        ("POST", "/v1/room-members/invitations"),
        ("GET", "/v1/room-members/capabilities"),
        ("POST", "/v1/room-members/grants/refresh"),
        ("POST", "/v1/room-members/grants/revoke"),
    ]
    assert [(method, path) for method, path, _ in run_routes] == [
        ("POST", "/v1/runs"),
        ("GET", "/v1/runs/{run_id}"),
        ("GET", "/v1/runs/{run_id}/events"),
        ("POST", "/v1/runs/{run_id}/approval"),
        ("POST", "/v1/runs/{run_id}/steer"),
        ("POST", "/v1/runs/{run_id}/stop"),
    ]
    assert all(handler.__self__ is adapter for _, _, handler in room_routes)
    assert all(handler.__self__ is adapter for _, _, handler in run_routes)
