import uuid
from datetime import datetime
from unittest.mock import AsyncMock, patch

import pytest

from app.main import app
from app.api.deps import get_current_user


@pytest.fixture
def mock_registered_user():
    """Return a mock user representing a successfully registered user."""
    user = AsyncMock()
    user.id = uuid.UUID("12345678-1234-1234-1234-123456789abc")
    user.email = "new@example.com"
    user.name = "New User"
    user.plan = "free"
    user.max_queries = 5
    user.is_active = True
    user.created_at = datetime.now()
    return user


@pytest.mark.asyncio
async def test_register_success(async_client, mock_registered_user):
    with patch("app.api.auth.register_user", return_value=mock_registered_user):
        response = await async_client.post(
            "/api/v1/auth/register",
            json={
                "email": "new@example.com",
                "password": "password123",
                "name": "New User",
            },
        )
    assert response.status_code == 201
    data = response.json()
    assert data["email"] == "new@example.com"
    assert data["name"] == "New User"


@pytest.mark.asyncio
async def test_register_duplicate_email(async_client):
    with patch(
        "app.api.auth.register_user",
        side_effect=ValueError("Email already registered"),
    ):
        response = await async_client.post(
            "/api/v1/auth/register",
            json={
                "email": "existing@example.com",
                "password": "password123",
                "name": "Existing User",
            },
        )
    assert response.status_code == 400
    data = response.json()
    assert "Email already registered" in data["detail"]


@pytest.mark.asyncio
async def test_login_success(async_client, mock_registered_user):
    with patch("app.api.auth.authenticate_user", return_value=mock_registered_user):
        response = await async_client.post(
            "/api/v1/auth/login",
            json={"email": "test@example.com", "password": "password123"},
        )
    assert response.status_code == 200
    data = response.json()
    assert "access_token" in data
    assert data["token_type"] == "bearer"
    assert data["user"]["email"] == "new@example.com"


@pytest.mark.asyncio
async def test_login_wrong_password(async_client):
    with patch("app.api.auth.authenticate_user", return_value=None):
        response = await async_client.post(
            "/api/v1/auth/login",
            json={"email": "test@example.com", "password": "wrongpassword"},
        )
    assert response.status_code == 401
    data = response.json()
    assert "Incorrect email or password" in data["detail"]


@pytest.mark.asyncio
async def test_get_me_authenticated(
    async_client, override_get_current_user, auth_headers
):
    response = await async_client.get("/api/v1/auth/me", headers=auth_headers)
    assert response.status_code == 200
    data = response.json()
    assert data["email"] == "test@example.com"
    assert data["name"] == "Test User"


@pytest.mark.asyncio
async def test_get_me_unauthenticated(async_client):
    # Ensure no auth override is active
    app.dependency_overrides.pop(get_current_user, None)
    response = await async_client.get("/api/v1/auth/me")
    assert response.status_code == 401
