"""Tests for users API endpoints."""

import pytest
from uuid import UUID

from vikdata.client import VikdataClient
from vikdata.exceptions import ResourceNotFoundError, ValidationError, ConflictError
from vikdata.models.user import (
    UserCreate,
    UserListParams,
    UserListResponse,
    UserResponse,
    UserUpdate,
)


@pytest.fixture
def mock_user():
    """Mock user data."""
    return {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "tenant_id": "550e8400-e29b-41d4-a716-446655440001",
        "email": "user@example.com",
        "display_name": "Test User",
        "avatar_url": None,
        "is_active": True,
        "metadata": None,
        "email_verified_at": "2025-01-01T00:00:00Z",
        "last_login_at": "2025-01-15T10:30:00Z",
        "created_at": "2025-01-01T00:00:00Z",
        "updated_at": "2025-01-15T10:30:00Z",
        "roles": [
            {
                "id": "550e8400-e29b-41d4-a716-446655440002",
                "name": "Member",
                "slug": "member",
            }
        ],
    }


@pytest.fixture
def mock_users_list(mock_user):
    """Mock users list response."""
    return {
        "data": [mock_user],
        "meta": {
            "page": 1,
            "per_page": 20,
            "total": 1,
            "total_pages": 1,
        },
    }


@pytest.mark.asyncio
async def test_list_users(respx_mock, mock_users_list):
    """Test listing users."""
    respx_mock.get("http://localhost:8000/api/v1/users").mock(
        return_value={"json": mock_users_list, "status_code": 200}
    )

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

        assert isinstance(response, UserListResponse)
        assert len(response.data) == 1
        assert response.data[0].email == "user@example.com"


@pytest.mark.asyncio
async def test_list_users_with_filters(respx_mock, mock_users_list):
    """Test listing users with query parameters."""
    respx_mock.get("http://localhost:8000/api/v1/users").mock(
        return_value={"json": mock_users_list, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        params = UserListParams(page=1, per_page=10, search="test", is_active=True)
        response = await client.users.list(params)

        assert isinstance(response, UserListResponse)


@pytest.mark.asyncio
async def test_get_user(respx_mock, mock_user):
    """Test getting a user by ID."""
    user_id = "550e8400-e29b-41d4-a716-446655440000"
    respx_mock.get(f"http://localhost:8000/api/v1/users/{user_id}").mock(
        return_value={"json": mock_user, "status_code": 200}
    )

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

        assert isinstance(response, UserResponse)
        assert str(response.id) == user_id
        assert response.email == "user@example.com"


@pytest.mark.asyncio
async def test_get_user_not_found(respx_mock):
    """Test getting a non-existent user."""
    user_id = "550e8400-e29b-41d4-a716-446655440099"
    respx_mock.get(f"http://localhost:8000/api/v1/users/{user_id}").mock(
        return_value={
            "json": {"message": "User 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.users.get(user_id)


@pytest.mark.asyncio
async def test_create_user(respx_mock, mock_user):
    """Test creating a new user."""
    respx_mock.post("http://localhost:8000/api/v1/users").mock(
        return_value={"json": mock_user, "status_code": 201}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        user_data = UserCreate(
            email="user@example.com",
            display_name="Test User",
            password="securepassword123",
            roles=["member"],
        )
        response = await client.users.create(user_data)

        assert isinstance(response, UserResponse)
        assert response.email == "user@example.com"


@pytest.mark.asyncio
async def test_create_user_duplicate_email(respx_mock):
    """Test creating a user with duplicate email."""
    respx_mock.post("http://localhost:8000/api/v1/users").mock(
        return_value={
            "json": {"message": "User with this email already exists"},
            "status_code": 409,
        }
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        user_data = UserCreate(email="existing@example.com", display_name="Test User")
        with pytest.raises(ConflictError):
            await client.users.create(user_data)


@pytest.mark.asyncio
async def test_update_user(respx_mock, mock_user):
    """Test updating a user."""
    user_id = "550e8400-e29b-41d4-a716-446655440000"
    updated_user = {**mock_user, "display_name": "Updated Name"}

    respx_mock.patch(f"http://localhost:8000/api/v1/users/{user_id}").mock(
        return_value={"json": updated_user, "status_code": 200}
    )

    async with VikdataClient(
        base_url="http://localhost:8000", access_token="test_token"
    ) as client:
        update_data = UserUpdate(display_name="Updated Name")
        response = await client.users.update(user_id, update_data)

        assert isinstance(response, UserResponse)
        assert response.display_name == "Updated Name"


@pytest.mark.asyncio
async def test_delete_user(respx_mock):
    """Test deleting a user."""
    user_id = "550e8400-e29b-41d4-a716-446655440000"
    respx_mock.delete(f"http://localhost:8000/api/v1/users/{user_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.users.delete(user_id)
