from app.config import get_settings
from app.database import get_session
from app.health import get_ai_health_probe, get_computer_health_probe, get_redis_client
from app.main import app
from fastapi.testclient import TestClient


class HealthyRedis:
    async def ping(self):
        return True

    async def aclose(self):
        return None


class UnavailableRedis(HealthyRedis):
    async def ping(self):
        raise ConnectionError("not available")


class HealthyDatabase:
    async def execute(self, _statement):
        return 1


def test_optional_provider_health_is_honestly_unconfigured():
    class UnconfiguredAI:
        async def status(self):
            return "unconfigured"

    app.dependency_overrides[get_ai_health_probe] = lambda: UnconfiguredAI()
    client = TestClient(app)
    assert client.get("/health/ai").json() == {"status": "unconfigured", "service": "ai"}
    assert client.get("/health/browser").json() == {
        "status": "unconfigured", "service": "browser"}
    app.dependency_overrides.clear()


def test_ai_health_reports_internal_service_loss_without_details():
    class UnavailableAI:
        async def status(self):
            return "unavailable"

    app.dependency_overrides[get_ai_health_probe] = lambda: UnavailableAI()
    response = TestClient(app).get("/health/ai")
    assert response.status_code == 503
    assert response.json() == {"status": "unavailable", "service": "ai"}
    app.dependency_overrides.clear()


def test_redis_readiness_reports_success_and_failure_without_details():
    async def healthy_override():
        yield HealthyRedis()

    app.dependency_overrides[get_redis_client] = healthy_override
    client = TestClient(app)
    response = client.get("/health/redis")
    assert response.status_code == 200
    assert response.json() == {"status": "ok", "service": "redis"}

    async def unavailable_override():
        yield UnavailableRedis()

    app.dependency_overrides[get_redis_client] = unavailable_override
    response = client.get("/health/redis")
    assert response.status_code == 503
    assert response.json() == {"status": "unavailable", "service": "redis"}
    app.dependency_overrides.clear()


def test_aggregate_readiness_requires_database_and_redis():
    async def database_override():
        yield HealthyDatabase()

    async def redis_override():
        yield HealthyRedis()

    app.dependency_overrides[get_session] = database_override
    app.dependency_overrides[get_redis_client] = redis_override
    response = TestClient(app).get("/health/readiness")
    assert response.status_code == 200
    assert response.json() == {"status": "ready", "service": "core-api"}

    async def unavailable_override():
        yield UnavailableRedis()

    app.dependency_overrides[get_redis_client] = unavailable_override
    response = TestClient(app).get("/health/readiness")
    assert response.status_code == 503
    assert response.json() == {"status": "unavailable", "service": "core-api"}
    app.dependency_overrides.clear()


def test_production_readiness_fails_closed_when_required_security_material_is_missing():
    async def database_override():
        yield HealthyDatabase()

    async def redis_override():
        yield HealthyRedis()

    settings = get_settings()
    prior_environment = settings.app_env
    prior_computer_token = settings.computer_service_token
    prior_computer_file = settings.computer_service_token_file
    settings.app_env = "production"
    settings.computer_service_token = None
    settings.computer_service_token_file = None
    app.dependency_overrides[get_session] = database_override
    app.dependency_overrides[get_redis_client] = redis_override
    try:
        response = TestClient(app).get("/health/readiness", headers={"host": "localhost"})
        assert response.status_code == 503
        assert response.json() == {"status": "unconfigured", "service": "core-api"}
    finally:
        settings.app_env = prior_environment
        settings.computer_service_token = prior_computer_token
        settings.computer_service_token_file = prior_computer_file
        app.dependency_overrides.clear()


def test_production_readiness_requires_configured_internal_workers(monkeypatch):
    class Probe:
        def __init__(self, status):
            self.value = status

        async def status(self):
            return self.value

    async def database_override():
        yield HealthyDatabase()

    async def redis_override():
        yield HealthyRedis()

    settings = get_settings()
    prior_environment = settings.app_env
    settings.app_env = "production"
    monkeypatch.setattr(type(settings), "production_configuration_errors", lambda _self: [])
    app.dependency_overrides[get_session] = database_override
    app.dependency_overrides[get_redis_client] = redis_override
    app.dependency_overrides[get_ai_health_probe] = lambda: Probe("configured")
    app.dependency_overrides[get_computer_health_probe] = lambda: Probe("unavailable")
    try:
        response = TestClient(app).get("/health/readiness", headers={"host": "localhost"})
        assert response.status_code == 503
        assert response.json() == {"status": "unavailable", "service": "core-api"}
        app.dependency_overrides[get_computer_health_probe] = lambda: Probe("configured")
        response = TestClient(app).get("/health/readiness", headers={"host": "localhost"})
        assert response.status_code == 200
        assert response.json() == {"status": "ready", "service": "core-api"}
    finally:
        settings.app_env = prior_environment
        app.dependency_overrides.clear()


def test_production_rejects_unexpected_public_host():
    settings = get_settings()
    prior_environment = settings.app_env
    prior_base_url = settings.app_base_url
    settings.app_env = "production"
    settings.app_base_url = "https://hayva.company.tld"
    try:
        response = TestClient(app).get("/health", headers={"host": "attacker.invalid"})
        assert response.status_code == 400
        assert response.json()["error"]["code"] == "INVALID_HOST"
        response = TestClient(app).get("/health", headers={"host": "hayva.company.tld"})
        assert response.status_code == 200
    finally:
        settings.app_env = prior_environment
        settings.app_base_url = prior_base_url
