"""健康检查API测试"""
import pytest
import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession, create_async_engine
from sqlalchemy.pool import StaticPool

from app.database import Base
from app.main import app
from app.api.deps import get_db


# ==================== Fixtures ====================

@pytest_asyncio.fixture
async def async_engine():
    """创建测试用SQLite异步引擎"""
    engine = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        connect_args={"check_same_thread": False},
        poolclass=StaticPool,
    )
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield engine
    await engine.dispose()


@pytest_asyncio.fixture
async def async_session(async_engine):
    """创建测试用异步数据库会话"""
    async_session_maker = async_sessionmaker(
        async_engine,
        class_=AsyncSession,
        expire_on_commit=False,
        autoflush=False,
        autocommit=False,
    )
    async with async_session_maker() as session:
        yield session


@pytest_asyncio.fixture
async def async_client(async_session):
    """创建异步HTTP客户端用于API测试"""

    async def override_get_db():
        yield async_session

    app.dependency_overrides[get_db] = override_get_db

    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        yield client

    app.dependency_overrides.clear()


# ==================== 测试类 ====================

class TestHealthAPI:
    """健康检查API测试"""

    @pytest.mark.asyncio
    async def test_basic_health(self):
        """测试基本健康检查"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/health")

            assert response.status_code == 200
            data = response.json()
            assert data["status"] == "healthy"
            assert "timestamp" in data

    @pytest.mark.asyncio
    async def test_liveness(self):
        """测试存活探针"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/health/liveness")

            assert response.status_code == 200
            data = response.json()
            assert data["status"] == "alive"

    @pytest.mark.asyncio
    async def test_ready_endpoint(self):
        """测试就绪端点"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/ready")

            # 返回200或503取决于依赖服务状态
            assert response.status_code in [200, 503]
            data = response.json()
            assert "status" in data
            assert "checks" in data
            assert "database" in data["checks"]
            assert "redis" in data["checks"]

    @pytest.mark.asyncio
    async def test_metrics(self):
        """测试Prometheus指标端点"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/metrics")

            assert response.status_code == 200
            # Prometheus指标返回文本格式
            assert "text/plain" in response.headers["content-type"] or \
                   "text/plain" in str(response.headers.get("content-type", ""))

    @pytest.mark.asyncio
    async def test_detailed_health(self, async_client):
        """测试详细健康检查"""
        response = await async_client.get("/health/detailed")

        assert response.status_code == 200
        data = response.json()
        # 检查返回结构
        assert "checks" in data
        assert "app" in data

    @pytest.mark.asyncio
    async def test_readiness_probe(self, async_client):
        """测试就绪探针"""
        response = await async_client.get("/health/readiness")

        # 健康状态应该是200，unhealthy是503
        assert response.status_code in [200, 503]
        data = response.json()
        assert "status" in data
        assert "checks" in data


class TestHealthEndpointsStructure:
    """健康检查端点结构测试"""

    @pytest.mark.asyncio
    async def test_health_endpoint_returns_json(self):
        """测试健康端点返回JSON格式"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/health")

            assert response.status_code == 200
            assert "application/json" in response.headers.get("content-type", "")

    @pytest.mark.asyncio
    async def test_detailed_health_has_required_fields(self, async_client):
        """测试详细健康检查包含必需字段"""
        response = await async_client.get("/health/detailed")

        assert response.status_code == 200
        data = response.json()

        # 检查app信息
        if "app" in data:
            app_info = data["app"]
            assert isinstance(app_info, dict)

    @pytest.mark.asyncio
    async def test_ready_checks_database_and_redis(self, async_client):
        """测试就绪检查包含数据库和Redis检查"""
        response = await async_client.get("/ready")

        data = response.json()
        checks = data.get("checks", {})

        assert "database" in checks
        assert "redis" in checks


class TestHealthCheckIndependence:
    """健康检查独立性测试"""

    @pytest.mark.asyncio
    async def test_health_no_auth_required(self):
        """测试健康检查不需要认证"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            # 不带token访问
            response = await client.get("/health")

            assert response.status_code == 200

    @pytest.mark.asyncio
    async def test_liveness_no_auth_required(self):
        """测试存活探针不需要认证"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/health/liveness")

            assert response.status_code == 200

    @pytest.mark.asyncio
    async def test_metrics_no_auth_required(self):
        """测试指标端点不需要认证"""
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            response = await client.get("/metrics")

            assert response.status_code == 200
