"""
认证集成测试

测试完整的认证流程，包括注册、登录、令牌刷新、登出等。
需要 PostgreSQL 数据库才能运行。在没有数据库的环境中会被跳过。
"""

import os
import uuid

import pytest
from fastapi.testclient import TestClient

# 检测是否有可用的 PostgreSQL 数据库
_HAS_PG = False
try:
    if os.environ.get("USE_IN_MEMORY_DB", "").lower() != "true":
        import psycopg

        conn = psycopg.connect(
            os.environ.get(
                "DATABASE_URL",
                "postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas",
            ).replace("postgresql+psycopg://", "postgresql://"),
            connect_timeout=3,
        )
        conn.close()
        _HAS_PG = True
except Exception:
    pass

needs_pg = pytest.mark.skipif(not _HAS_PG, reason="Requires PostgreSQL database")

from apps.api.main import app

client = TestClient(app)


@needs_pg
class TestUserRegistration:
    """用户注册集成测试"""

    def test_register_with_valid_data(self):
        """测试使用有效数据进行注册"""
        unique = uuid.uuid4().hex[:8]
        response = client.post(
            "/api/v1/auth/register",
            json={
                "email": f"newuser-{unique}@example.com",
                "password": "SecurePass123",
                "username": f"newuser-{unique}",
                "display_name": "New User",
            },
        )

        assert response.status_code in (200, 201)
        data = response.json()
        assert data["username"] == f"newuser-{unique}"
        assert "user_id" in data
        assert "message" in data

    def test_register_with_invalid_email(self):
        """测试使用无效邮箱进行注册"""
        response = client.post(
            "/api/v1/auth/register",
            json={
                "email": "invalid-email",
                "password": "SecurePass123",
                "username": "testuser",
            },
        )

        assert response.status_code == 422

    def test_register_with_weak_password(self):
        """测试使用弱密码进行注册"""
        response = client.post(
            "/api/v1/auth/register",
            json={
                "email": "weak@example.com",
                "password": "123",
                "username": "weakuser",
            },
        )

        assert response.status_code in [400, 422]

    def test_register_duplicate_email(self):
        """测试重复邮箱注册"""
        unique = uuid.uuid4().hex[:8]
        email = f"dup-{unique}@example.com"

        client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": "SecurePass123",
                "username": f"user1-{unique}",
                "display_name": "User 1",
            },
        )

        response = client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": "SecurePass123",
                "username": f"user2-{unique}",
                "display_name": "User 2",
            },
        )

        assert response.status_code == 400
        body = response.json()
        message = body.get("detail", "") or body.get("error", {}).get("message", "")
        assert "邮箱" in message or "already" in message.lower() or "注册" in message


@needs_pg
class TestUserLogin:
    """用户登录集成测试"""

    def setup_method(self):
        """每个测试前的准备：注册用户"""
        self.test_email = f"login-{uuid.uuid4().hex[:8]}@example.com"
        self.test_username = f"loginuser-{uuid.uuid4().hex[:8]}"

        register_response = client.post(
            "/api/v1/auth/register",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
                "username": self.test_username,
                "display_name": "Login User",
            },
        )
        assert register_response.status_code in (200, 201), f"Register failed: {register_response.json()}"

    def test_login_with_correct_credentials(self):
        """测试使用正确凭据登录"""
        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert "access_token" in data
        assert "refresh_token" in data
        assert data["token_type"] == "bearer"

    def test_login_with_wrong_password(self):
        """测试使用错误密码登录"""
        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": self.test_email,
                "password": "WrongPassword123",
            },
        )

        assert response.status_code == 401

    def test_login_with_nonexistent_email(self):
        """测试使用不存在的邮箱登录"""
        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": "nonexistent@example.com",
                "password": "AnyPassword123",
            },
        )

        assert response.status_code == 401

    def test_login_case_insensitive_email(self):
        """测试邮箱大小写不敏感登录"""
        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": self.test_email.upper(),
                "password": "SecurePass123",
            },
        )

        assert response.status_code == 200


@needs_pg
class TestTokenRefresh:
    """令牌刷新集成测试"""

    def setup_method(self):
        """每个测试前的准备：注册并登录获取令牌"""
        self.test_email = f"refresh-{uuid.uuid4().hex[:8]}@example.com"

        client.post(
            "/api/v1/auth/register",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
                "username": f"refreshuser-{uuid.uuid4().hex[:8]}",
                "display_name": "Refresh User",
            },
        )

        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
            },
        )
        self.refresh_token = response.json().get("refresh_token") if response.status_code == 200 else None

    def test_refresh_token_success(self):
        """测试成功刷新令牌"""
        if not self.refresh_token:
            pytest.skip("Refresh token not available")

        response = client.post(
            "/api/v1/auth/refresh",
            json={"refresh_token": self.refresh_token},
        )

        if response.status_code not in (404, 401):
            assert response.status_code == 200
            data = response.json()
            assert "access_token" in data


@needs_pg
class TestCurrentUser:
    """当前用户信息集成测试"""

    def setup_method(self):
        """每个测试前的准备：注册并登录获取令牌"""
        self.test_email = f"me-{uuid.uuid4().hex[:8]}@example.com"

        client.post(
            "/api/v1/auth/register",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
                "username": f"meuser-{uuid.uuid4().hex[:8]}",
                "display_name": "Me User",
            },
        )

        response = client.post(
            "/api/v1/auth/login",
            json={
                "email": self.test_email,
                "password": "SecurePass123",
            },
        )

        if response.status_code != 200:
            pytest.skip("Login failed during setup")

        self.token = response.json().get("access_token")
        self.headers = {"Authorization": f"Bearer {self.token}"} if self.token else {}

    def test_get_current_user_success(self):
        """测试获取当前用户信息成功"""
        if not self.token:
            pytest.skip("Token not available")

        response = client.get("/api/v1/auth/me", headers=self.headers)
        assert response.status_code == 200
        data = response.json()
        assert data["email"] == self.test_email
        assert "user_id" in data

    def test_get_current_user_without_token(self):
        """测试无令牌获取当前用户信息"""
        response = client.get("/api/v1/auth/me")
        assert response.status_code in [401, 403]

    def test_get_current_user_with_invalid_token(self):
        """测试使用无效令牌获取当前用户信息"""
        response = client.get(
            "/api/v1/auth/me",
            headers={"Authorization": "Bearer invalid-token"},
        )
        assert response.status_code in [401, 403]


@needs_pg
class TestPasswordReset:
    """密码重置集成测试"""

    def test_request_password_reset_success(self):
        """测试请求密码重置成功"""
        test_email = f"reset-{uuid.uuid4().hex[:8]}@example.com"

        client.post(
            "/api/v1/auth/register",
            json={
                "email": test_email,
                "password": "SecurePass123",
                "username": f"resetuser-{uuid.uuid4().hex[:8]}",
                "display_name": "Reset User",
            },
        )

        response = client.post(
            "/api/v1/auth/forgot-password",
            json={"email": test_email},
        )

        # API returns 200 or 202 on success
        assert response.status_code in (200, 202)

    def test_request_password_reset_nonexistent_user(self):
        """测试请求不存在的用户密码重置"""
        response = client.post(
            "/api/v1/auth/forgot-password",
            json={"email": "nonexistent@example.com"},
        )

        # API returns 200/202 for non-existent user (security: don't reveal email existence)
        assert response.status_code in [200, 202, 400]


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