"""Tests for API keys API endpoints."""

import pytest
from datetime import datetime, UTC
from uuid import UUID

from vikdata.client import VikdataClient
from vikdata.exceptions import ResourceNotFoundError, ValidationError
from vikdata.models.api_key import (
    ApiKeyCreate,
    ApiKeyCreateResponse,
    ApiKeyListResponse,
    ApiKeyWithRolesResponse,
)


@pytest.fixture
def mock_api_key():
    """Mock API key data."""
    return {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Production API Key",
        "key_prefix": "vk_live_xxxx",
        "description": "Production key",
        "tenant_id": "550e8400-e29b-41d4-a716-446655440001",
        "is_revoked": False,
        "last_used_at": "2025-01-15T10:30:00Z",
        "expires_at": None,
        "created_at": "2025-01-01T00:00:00Z",
        "roles": [
            {
                "id": "550e8400-e29b-41d4-a716-446655440002",
                "name": "API Access",
                "slug": "api-access",
            }
        ],
    }


@pytest.fixture
def mock_api_keys_list(mock_api_key):
    """Mock API keys list response."""
    return {"data": [mock_api_key]}


@pytest.mark.asyncio
async def test_list_api_keys(respx_mock, mock_api_keys_list):
    """Test listing API keys."""
    respx_mock.get("http://localhost:8000/api/v1/api-keys").mock(
        return_value={"json": mock_api_keys_list, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.list()

        assert isinstance(response, ApiKeyListResponse)
        assert len(response.data) == 1
        assert response.data[0].name == "Production API Key"


@pytest.mark.asyncio
async def test_list_api_keys_with_revoked(respx_mock, mock_api_keys_list):
    """Test listing API keys including revoked ones."""
    respx_mock.get("http://localhost:8000/api/v1/api-keys").mock(
        return_value={"json": mock_api_keys_list, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.list(include_revoked=True)

        assert isinstance(response, ApiKeyListResponse)


@pytest.mark.asyncio
async def test_get_api_key(respx_mock, mock_api_key):
    """Test getting an API key by ID."""
    key_id = "550e8400-e29b-41d4-a716-446655440000"
    respx_mock.get(f"http://localhost:8000/api/v1/api-keys/{key_id}").mock(
        return_value={"json": mock_api_key, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.get(UUID(key_id))

        assert isinstance(response, ApiKeyWithRolesResponse)
        assert str(response.id) == key_id
        assert response.name == "Production API Key"


@pytest.mark.asyncio
async def test_create_api_key(respx_mock):
    """Test creating a new API key."""
    role_id = UUID("550e8400-e29b-41d4-a716-446655440002")
    created_key = {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "New API Key",
        "key": "vk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
        "key_prefix": "vk_live_a1b2",
        "description": "Test key",
        "expires_at": "2026-01-15T00:00:00Z",
        "created_at": "2025-01-15T10:30:00Z",
    }

    respx_mock.post("http://localhost:8000/api/v1/api-keys").mock(
        return_value={"json": created_key, "status_code": 201}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.create(
            name="New API Key",
            role_ids=[role_id],
            description="Test key",
            expires_at=datetime(2026, 1, 15, tzinfo=UTC),
        )

        assert isinstance(response, ApiKeyCreateResponse)
        assert response.name == "New API Key"
        assert response.key == "vk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"


@pytest.mark.asyncio
async def test_update_api_key_roles(respx_mock, mock_api_key):
    """Test updating API key roles."""
    key_id = "550e8400-e29b-41d4-a716-446655440000"
    role_id = UUID("550e8400-e29b-41d4-a716-446655440002")

    respx_mock.patch(f"http://localhost:8000/api/v1/api-keys/{key_id}/roles").mock(
        return_value={"json": mock_api_key, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.update_roles(UUID(key_id), [role_id])

        assert isinstance(response, ApiKeyWithRolesResponse)


@pytest.mark.asyncio
async def test_revoke_api_key(respx_mock):
    """Test revoking an API key."""
    key_id = "550e8400-e29b-41d4-a716-446655440000"
    respx_mock.delete(f"http://localhost:8000/api/v1/api-keys/{key_id}").mock(
        return_value={"status_code": 204}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        # Should not raise an exception
        await client.api_keys.revoke(UUID(key_id))


@pytest.mark.asyncio
async def test_rotate_api_key(respx_mock):
    """Test rotating an API key."""
    key_id = "550e8400-e29b-41d4-a716-446655440000"
    rotated_key = {
        "old_key_id": key_id,
        "new_key": {
            "id": "550e8400-e29b-41d4-a716-446655440099",
            "name": "Production API Key",
            "key": "vk_live_newkeynewkeynewkeynewkeynewkey",
            "key_prefix": "vk_live_newk",
            "created_at": "2025-01-15T10:30:00Z",
        },
    }

    respx_mock.post(f"http://localhost:8000/api/v1/api-keys/{key_id}/rotate").mock(
        return_value={"json": rotated_key, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        response = await client.api_keys.rotate(UUID(key_id))

        assert response.old_key_id == UUID(key_id)
        assert response.new_key.key == "vk_live_newkeynewkeynewkeynewkeynewkey"


@pytest.mark.asyncio
async def test_get_api_key_not_found(respx_mock):
    """Test getting a non-existent API key."""
    key_id = "550e8400-e29b-41d4-a716-446655440099"
    respx_mock.get(f"http://localhost:8000/api/v1/api-keys/{key_id}").mock(
        return_value={
            "json": {"message": "API key not found"},
            "status_code": 404,
        }
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        with pytest.raises(ResourceNotFoundError):
            await client.api_keys.get(UUID(key_id))
