"""
Integration tests for health check endpoints.

These hit the actual FastAPI app via TestClient, but mock out the
heavy startup dependencies (model loading, DB, Redis, reference data
file I/O) since the full test suite should not require live
infrastructure or real model files to run in CI. For a true end-to-end
smoke test against real infrastructure, see deployment/scripts/deploy.sh's
post-deploy health check instead.

The FastAPI lifespan (app/main.py) calls model_registry.load_all(),
feature_builder.load(), reference_data.load(), and cache_service.init()
for real on startup — each of these touches the filesystem or network.
For these tests we patch the *load* methods themselves to no-ops and
pre-set the internal state they would have populated, so the lifespan
completes without requiring real models/data/services to exist.
"""

from unittest.mock import AsyncMock, patch

import pytest
from fastapi.testclient import TestClient


@pytest.fixture
def client():
    fake_models = {
        "sarimax_climate": {}, "xgb_feasibility": {}, "xgb_yield": {},
        "dt_trend": {}, "rf_recommendation": {}, "sarimax_market": {},
    }

    with patch("app.models_loader.registry.model_registry.load_all", return_value=None), \
         patch("app.models_loader.registry.model_registry._loaded", True), \
         patch("app.models_loader.registry.model_registry._models", fake_models), \
         patch("app.services.feature_builder.feature_builder.load", return_value=None), \
         patch("app.services.reference_data.reference_data.load", return_value=None), \
         patch("app.services.reference_data.reference_data._loaded", True), \
         patch("app.services.llm_service.llm_service.init", return_value=None), \
         patch("app.services.cache_service.cache_service.init", new=AsyncMock(return_value=None)), \
         patch("app.services.cache_service.cache_service.health_check", new=AsyncMock(return_value=True)), \
         patch("app.db.session.check_db_connection", new=AsyncMock(return_value=True)), \
         patch("app.db.session.dispose_engine", new=AsyncMock(return_value=None)):

        from app.main import app
        with TestClient(app) as test_client:
            yield test_client


class TestLivenessEndpoint:
    def test_liveness_returns_200(self, client):
        response = client.get("/api/v1/health/live")
        assert response.status_code == 200
        assert response.json()["status"] == "alive"


class TestReadinessEndpoint:
    def test_readiness_returns_200_when_all_healthy(self, client):
        response = client.get("/api/v1/health/ready")
        assert response.status_code == 200
        body = response.json()
        assert body["status"] == "ready"
        assert body["checks"]["database"] == "ok"
        assert body["checks"]["models_loaded"] == "ok"


class TestRootEndpoint:
    def test_root_returns_service_info(self, client):
        response = client.get("/")
        assert response.status_code == 200
        body = response.json()
        assert "service" in body
        assert "version" in body
