import pytest

from memory_layer_client import AsyncMemoryClient, MemoryScope


def _scope() -> MemoryScope:
    return MemoryScope(
        tenant_id="acme",
        system_id="executor",
        scope_id="run-b",
        workspace_id="factory",
        collaboration_id="release-42",
    )


@pytest.mark.asyncio
async def test_async_client_supports_inspection_and_health(httpx_mock) -> None:
    scope = _scope()
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/inspect/knowledge?limit=20&tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        json={"items": [{"id": 9, "fact": "rollback"}], "hasMore": False, "nextCursor": None},
    )
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/inspect/reverification?limit=5&tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        json={"due": [{"id": 9, "fact": "rollback"}]},
    )
    httpx_mock.add_response(method="GET", url="http://test/healthz", json={"ok": True, "scopes": 2})

    client = AsyncMemoryClient("http://test", default_scope=scope)
    listing = await client.list_knowledge(limit=20)
    due = await client.inspect_reverification(limit=5)
    live = await client.live()
    await client.aclose()

    assert listing.items[0]["id"] == 9
    assert due.due[0]["fact"] == "rollback"
    assert live.ok is True


@pytest.mark.asyncio
async def test_async_client_can_stream_events(httpx_mock) -> None:
    scope = _scope()
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/events?event_types=knowledge_change&scope_level=workspace&tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        text='data: {"type":"connected"}\n\ndata: {"type":"knowledge_change","scope":{"tenant_id":"acme"},"timestamp":1,"durationMs":0,"meta":{"action":"promote"}}\n\n',
        headers={"content-type": "text/event-stream"},
    )

    async with AsyncMemoryClient("http://test", default_scope=scope) as client:
        events = []
        async for event in client.astream_events(
            event_types=["knowledge_change"],
            scope_level="workspace",
        ):
            events.append(event)

    assert events[0].type == "knowledge_change"
    assert events[0].meta["action"] == "promote"


@pytest.mark.asyncio
async def test_async_client_can_poll_changes_by_cursor(httpx_mock) -> None:
    scope = _scope()
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/changes?cursor=23&scope_level=workspace&tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        json={
            "changes": [
                {
                    "event_id": "24",
                    "event_type": "knowledge.updated",
                    "id": 9,
                    "fact": "rollback",
                }
            ],
            "nextCursor": "24",
        },
    )

    async with AsyncMemoryClient("http://test", default_scope=scope) as client:
        changes = await client.poll_changes(cursor=23, scope_level="workspace")

    assert changes.changes[0]["event_type"] == "knowledge.updated"
    assert changes.next_cursor == "24"


@pytest.mark.asyncio
async def test_async_client_supports_coordination_endpoints(httpx_mock) -> None:
    scope = _scope()
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/handoffs?tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        json={"handoffs": []},
    )
    httpx_mock.add_response(
        method="GET",
        url="http://test/v1/changes/stream?cursor=7&tenant_id=acme&system_id=executor&scope_id=run-b&workspace_id=factory&collaboration_id=release-42",
        text='data: {"type":"connected","cursor":7}\n\ndata: {"event_id":8,"entity_kind":"handoff","entity_id":"2","event_type":"handoff.created","payload":{},"created_at":9}\n\n',
        headers={"content-type": "text/event-stream"},
    )

    async with AsyncMemoryClient("http://test", default_scope=scope) as client:
        handoffs = await client.list_pending_handoffs()
        events = []
        async for event in client.astream_changes(cursor=7):
            events.append(event)

    assert handoffs.handoffs == []
    assert events[0].event_type == "handoff.created"
