import pytest
import json
from httpx import AsyncClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from app.main import app
from app.core.database import get_db, Base
from app.core.config import settings
from app.models.user import User

# 测试数据库配置
SQLALCHEMY_DATABASE_URL = "sqlite:///./test_auth.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

@pytest.fixture(scope="function")
def db_session():
    """创建测试数据库会话"""
    Base.metadata.create_all(bind=engine)
    session = TestingSessionLocal()
    try:
        yield session
    finally:
        session.close()
        Base.metadata.drop_all(bind=engine)

@pytest.fixture(scope="function")
def client(db_session):
    """创建测试客户端"""
    def override_get_db():
        try:
            yield db_session
        finally:
            pass

    app.dependency_overrides[get_db] = override_get_db

    with AsyncClient(app=app, base_url="http://test") as ac:
        yield ac

    app.dependency_overrides.clear()

@pytest.fixture
def test_user_data():
    """测试用户数据"""
    return {
        "username": "testuser123",
        "email": "test123@example.com",
        "password": "TestPass123!",
        "confirm_password": "TestPass123!"
    }

@pytest.mark.asyncio
async def test_register_user_success(client: AsyncClient, test_user_data):
    """测试用户注册成功"""
    response = await client.post("/api/v1/auth/register", json=test_user_data)

    assert response.status_code == 201
    data = response.json()
    assert data["success"] is True
    assert "user" in data["data"]
    assert "tokens" in data["data"]
    assert data["data"]["user"]["username"] == test_user_data["username"]
    assert data["data"]["user"]["email"] == test_user_data["email"]
    assert "access_token" in data["data"]["tokens"]
    assert "refresh_token" in data["data"]["tokens"]

@pytest.mark.asyncio
async def test_register_user_username_exists(client: AsyncClient, test_user_data):
    """测试用户名已存在的情况"""
    # 先注册一个用户
    await client.post("/api/v1/auth/register", json=test_user_data)

    # 再次使用相同用户名注册
    response = await client.post("/api/v1/auth/register", json=test_user_data)

    assert response.status_code == 400
    data = response.json()
    assert data["detail"]["code"] == "USERNAME_EXISTS"

@pytest.mark.asyncio
async def test_register_user_email_exists(client: AsyncClient, test_user_data):
    """测试邮箱已存在的情况"""
    # 先注册一个用户
    await client.post("/api/v1/auth/register", json=test_user_data)

    # 使用相同邮箱但不同用户名注册
    duplicate_email_data = test_user_data.copy()
    duplicate_email_data["username"] = "differentuser"

    response = await client.post("/api/v1/auth/register", json=duplicate_email_data)

    assert response.status_code == 400
    data = response.json()
    assert data["detail"]["code"] == "EMAIL_EXISTS"

@pytest.mark.asyncio
async def test_register_user_invalid_email(client: AsyncClient, test_user_data):
    """测试无效邮箱"""
    invalid_data = test_user_data.copy()
    invalid_data["email"] = "invalid-email"

    response = await client.post("/api/v1/auth/register", json=invalid_data)

    assert response.status_code == 422  # Validation error

@pytest.mark.asyncio
async def test_register_user_weak_password(client: AsyncClient, test_user_data):
    """测试弱密码"""
    invalid_data = test_user_data.copy()
    invalid_data["password"] = "123"
    invalid_data["confirm_password"] = "123"

    response = await client.post("/api/v1/auth/register", json=invalid_data)

    assert response.status_code == 422  # Validation error

@pytest.mark.asyncio
async def test_register_user_password_mismatch(client: AsyncClient, test_user_data):
    """测试密码确认不匹配"""
    invalid_data = test_user_data.copy()
    invalid_data["confirm_password"] = "DifferentPass123!"

    response = await client.post("/api/v1/auth/register", json=invalid_data)

    assert response.status_code == 422  # Validation error

@pytest.mark.asyncio
async def test_login_user_success(client: AsyncClient, test_user_data):
    """测试用户登录成功"""
    # 先注册用户
    await client.post("/api/v1/auth/register", json=test_user_data)

    # 登录
    login_data = {
        "username": test_user_data["username"],
        "password": test_user_data["password"]
    }

    response = await client.post("/api/v1/auth/login", json=login_data)

    assert response.status_code == 200
    data = response.json()
    assert data["success"] is True
    assert "user" in data["data"]
    assert "tokens" in data["data"]
    assert data["data"]["user"]["username"] == test_user_data["username"]

@pytest.mark.asyncio
async def test_login_user_with_email(client: AsyncClient, test_user_data):
    """测试使用邮箱登录"""
    # 先注册用户
    await client.post("/api/v1/auth/register", json=test_user_data)

    # 使用邮箱登录
    login_data = {
        "username": test_user_data["email"],
        "password": test_user_data["password"]
    }

    response = await client.post("/api/v1/auth/login", json=login_data)

    assert response.status_code == 200
    data = response.json()
    assert data["success"] is True

@pytest.mark.asyncio
async def test_login_user_invalid_credentials(client: AsyncClient, test_user_data):
    """测试无效凭据登录"""
    # 先注册用户
    await client.post("/api/v1/auth/register", json=test_user_data)

    # 使用错误密码登录
    login_data = {
        "username": test_user_data["username"],
        "password": "WrongPassword123!"
    }

    response = await client.post("/api/v1/auth/login", json=login_data)

    assert response.status_code == 401
    data = response.json()
    assert data["detail"]["code"] == "INVALID_CREDENTIALS"

@pytest.mark.asyncio
async def test_login_user_not_exists(client: AsyncClient):
    """测试登录不存在的用户"""
    login_data = {
        "username": "nonexistentuser",
        "password": "SomePassword123!"
    }

    response = await client.post("/api/v1/auth/login", json=login_data)

    assert response.status_code == 401
    data = response.json()
    assert data["detail"]["code"] == "INVALID_CREDENTIALS"

@pytest.mark.asyncio
async def test_get_current_user_info(client: AsyncClient, test_user_data):
    """测试获取当前用户信息"""
    # 先注册用户
    register_response = await client.post("/api/v1/auth/register", json=test_user_data)
    access_token = register_response.json()["data"]["tokens"]["access_token"]

    # 获取用户信息
    headers = {"Authorization": f"Bearer {access_token}"}
    response = await client.get("/api/v1/auth/me", headers=headers)

    assert response.status_code == 200
    data = response.json()
    assert data["success"] is True
    assert data["data"]["user"]["username"] == test_user_data["username"]

@pytest.mark.asyncio
async def test_get_current_user_info_invalid_token(client: AsyncClient):
    """测试使用无效令牌获取用户信息"""
    headers = {"Authorization": "Bearer invalid_token"}
    response = await client.get("/api/v1/auth/me", headers=headers)

    assert response.status_code == 401

@pytest.mark.asyncio
async def test_get_current_user_info_no_token(client: AsyncClient):
    """测试不提供令牌获取用户信息"""
    response = await client.get("/api/v1/auth/me")

    assert response.status_code == 403  # HTTPBearer returns 403 for missing credentials

@pytest.mark.asyncio
async def test_refresh_token_success(client: AsyncClient, test_user_data):
    """测试令牌刷新成功"""
    # 先注册用户
    register_response = await client.post("/api/v1/auth/register", json=test_user_data)
    refresh_token = register_response.json()["data"]["tokens"]["refresh_token"]

    # 刷新令牌
    refresh_data = {"refresh_token": refresh_token}
    response = await client.post("/api/v1/auth/refresh", json=refresh_data)

    assert response.status_code == 200
    data = response.json()
    assert data["success"] is True
    assert "tokens" in data["data"]
    assert "access_token" in data["data"]["tokens"]
    assert "refresh_token" in data["data"]["tokens"]

@pytest.mark.asyncio
async def test_refresh_token_invalid(client: AsyncClient):
    """测试无效刷新令牌"""
    refresh_data = {"refresh_token": "invalid_refresh_token"}
    response = await client.post("/api/v1/auth/refresh", json=refresh_data)

    assert response.status_code == 401
    data = response.json()
    assert data["detail"]["code"] == "INVALID_REFRESH_TOKEN"

@pytest.mark.asyncio
async def test_logout_success(client: AsyncClient, test_user_data):
    """测试登出成功"""
    # 先注册用户
    register_response = await client.post("/api/v1/auth/register", json=test_user_data)
    access_token = register_response.json()["data"]["tokens"]["access_token"]

    # 登出
    headers = {"Authorization": f"Bearer {access_token}"}
    response = await client.post("/api/v1/auth/logout", headers=headers)

    assert response.status_code == 200
    data = response.json()
    assert data["success"] is True
    assert data["message"] == "登出成功"

@pytest.mark.asyncio
async def test_register_user_invalid_username(client: AsyncClient, test_user_data):
    """测试无效用户名"""
    invalid_data = test_user_data.copy()
    invalid_data["username"] = "us"  # 太短

    response = await client.post("/api/v1/auth/register", json=invalid_data)

    assert response.status_code == 422  # Validation error

@pytest.mark.asyncio
async def test_register_user_username_with_special_chars(client: AsyncClient, test_user_data):
    """测试用户名包含特殊字符"""
    invalid_data = test_user_data.copy()
    invalid_data["username"] = "user@name"  # 包含特殊字符

    response = await client.post("/api/v1/auth/register", json=invalid_data)

    assert response.status_code == 422  # Validation error

if __name__ == "__main__":
    pytest.main([__file__, "-v"])