from uuid import UUID
from unittest.mock import AsyncMock

import pytest

from dsg_core_client.client import DSGCoreClient


@pytest.mark.asyncio
async def test_list_events_calls_events_collection_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        get_mock = AsyncMock(return_value=[])
        setattr(client, "get_with_headers", get_mock)

        response = await client.events.list_events(
            event_types=["ItemCreatedEvent", "ItemUpdatedEvent"],
            limit=10,
            offset=5,
        )

        assert response == []
        get_mock.assert_awaited_once_with(
            client.path("/events"),
            headers={
                "event-types": "ItemCreatedEvent,ItemUpdatedEvent",
                "limit": "10",
                "offset": "5",
            },
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_list_aggregate_events_calls_history_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        aggregate_id = UUID("00000000-0000-0000-0000-000000000001")

        get_mock = AsyncMock(return_value=[])
        setattr(client, "get", get_mock)

        response = await client.events.list_aggregate_events(
            aggregate_id,
            version="2.0",
        )

        assert response == []
        get_mock.assert_awaited_once_with(
            client.path(f"/events/aggregate/{aggregate_id}/history"),
            params={"version": "2.0"},
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_events_calls_events_item_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")
        user_id = UUID("00000000-0000-0000-0000-000000000002")

        get_mock = AsyncMock(
            return_value=[
                {
                    "eventUid": "00000000-0000-0000-0000-000000000003",
                    "timestamp": "2026-01-01T00:00:00Z",
                    "release": 1,
                    "eventType": "ItemCreatedEvent",
                    "data": {"name": "item-1"},
                    "aggregateId": str(item_id),
                    "userUid": str(user_id),
                    "taskUid": None,
                }
            ]
        )
        setattr(client, "get", get_mock)

        response = await client.events.query_item_events(item_id)

        assert len(response) == 1
        assert response[0].event_type == "ItemCreatedEvent"
        assert response[0].aggregate_id == item_id
        get_mock.assert_awaited_once_with(client.path(f"/events/items/{item_id}"))
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_events_passes_version_query_param() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")

        get_mock = AsyncMock(return_value=[])
        setattr(client, "get", get_mock)

        _ = await client.events.query_item_events(item_id, version="2.0")

        get_mock.assert_awaited_once_with(
            client.path(f"/events/items/{item_id}"),
            params={"version": "2.0"},
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_last_event_calls_events_last_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")
        user_id = UUID("00000000-0000-0000-0000-000000000002")

        get_mock = AsyncMock(
            return_value={
                "eventUid": "00000000-0000-0000-0000-000000000003",
                "timestamp": "2026-01-01T00:00:00Z",
                "release": 2,
                "eventType": "ItemUpdatedEvent",
                "data": {"name": "item-2"},
                "aggregateId": str(item_id),
                "userUid": str(user_id),
                "taskUid": None,
            }
        )
        setattr(client, "get", get_mock)

        response = await client.events.query_item_last_event(item_id)

        assert response.event_type == "ItemUpdatedEvent"
        assert response.release == 2
        get_mock.assert_awaited_once_with(
            client.path(f"/events/items/{item_id}/last"),
            params=None,
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_last_event_passes_version_query_param() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")

        get_mock = AsyncMock(
            return_value={
                "eventUid": "00000000-0000-0000-0000-000000000003",
                "timestamp": "2026-01-01T00:00:00Z",
                "release": 2,
                "eventType": "ItemUpdatedEvent",
                "data": {"version": "2.0"},
                "aggregateId": str(item_id),
                "userUid": "00000000-0000-0000-0000-000000000002",
                "taskUid": None,
            }
        )
        setattr(client, "get", get_mock)

        _ = await client.events.query_item_last_event(item_id, version="2.0")

        get_mock.assert_awaited_once_with(
            client.path(f"/events/items/{item_id}/last"),
            params={"version": "2.0"},
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_last_n_events_calls_events_last_n_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")
        user_id = UUID("00000000-0000-0000-0000-000000000002")

        get_mock = AsyncMock(
            return_value=[
                {
                    "eventUid": "00000000-0000-0000-0000-000000000003",
                    "timestamp": "2026-01-01T00:00:00Z",
                    "release": 3,
                    "eventType": "ItemRetiredEvent",
                    "data": {},
                    "aggregateId": str(item_id),
                    "userUid": str(user_id),
                    "taskUid": None,
                }
            ]
        )
        setattr(client, "get", get_mock)

        response = await client.events.query_item_last_n_events(item_id, 5)

        assert len(response) == 1
        assert response[0].release == 3
        get_mock.assert_awaited_once_with(
            client.path(f"/events/items/{item_id}/last/5"),
            params=None,
        )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_query_item_last_n_events_passes_version_query_param() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        item_id = UUID("00000000-0000-0000-0000-000000000001")

        get_mock = AsyncMock(return_value=[])
        setattr(client, "get", get_mock)

        _ = await client.events.query_item_last_n_events(item_id, 5, version="2.0")

        get_mock.assert_awaited_once_with(
            client.path(f"/events/items/{item_id}/last/5"),
            params={"version": "2.0"},
        )
    finally:
        await client.close()
