# grantflow/tests/test_integration_readiness_warnings.py

from types import SimpleNamespace

from fastapi.testclient import TestClient

from grantflow.api import runtime_state
from grantflow.api.app import app
from grantflow.core.config import config
from grantflow.memory_bank.vector_store import vector_store

client = TestClient(app)


def test_health_endpoint_reports_chroma_port_conflict_warning(monkeypatch):
    monkeypatch.setattr(vector_store, "_chroma_host", "127.0.0.1")
    monkeypatch.setattr(vector_store, "_chroma_port", 8000)

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    warnings = body["diagnostics"].get("configuration_warnings") or []
    assert any(w.get("code") == "CHROMA_PORT_MAY_CONFLICT_WITH_API_DEFAULT" for w in warnings if isinstance(w, dict))


def test_health_endpoint_reports_tenant_authz_without_allowlist_warning(monkeypatch):
    monkeypatch.setenv("GRANTFLOW_TENANT_AUTHZ_ENABLED", "true")
    monkeypatch.delenv("GRANTFLOW_ALLOWED_TENANTS", raising=False)
    monkeypatch.delenv("AIDGRAPH_ALLOWED_TENANTS", raising=False)

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    warnings = body["diagnostics"].get("configuration_warnings") or []
    assert any(w.get("code") == "TENANT_AUTHZ_ENABLED_WITHOUT_ALLOWLIST" for w in warnings if isinstance(w, dict))


def test_health_endpoint_reports_default_tenant_not_in_allowlist_warning(monkeypatch):
    monkeypatch.setenv("GRANTFLOW_TENANT_AUTHZ_ENABLED", "true")
    monkeypatch.setenv("GRANTFLOW_ALLOWED_TENANTS", "tenant_alpha")
    monkeypatch.setenv("GRANTFLOW_DEFAULT_TENANT", "tenant_beta")

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    warnings = body["diagnostics"].get("configuration_warnings") or []
    assert any(w.get("code") == "TENANT_DEFAULT_NOT_IN_ALLOWLIST" for w in warnings if isinstance(w, dict))


def test_health_endpoint_reports_production_persistent_store_warnings(monkeypatch):
    class FakeJobStore:
        db_path = None

    class FakeHitlManager:
        _use_sqlite = False

    class FakeIngestAuditStore:
        db_path = None

    monkeypatch.setenv("GRANTFLOW_ENV", "production")
    monkeypatch.setenv("GRANTFLOW_REQUIRE_PERSISTENT_STORES_ON_STARTUP", "false")
    monkeypatch.setattr(runtime_state, "JOB_STORE", FakeJobStore())
    monkeypatch.setattr(runtime_state, "hitl_manager", FakeHitlManager())
    monkeypatch.setattr(runtime_state, "INGEST_AUDIT_STORE", FakeIngestAuditStore())

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    warnings = body["diagnostics"].get("configuration_warnings") or []
    assert any(
        w.get("code") == "PERSISTENT_STORE_STARTUP_GUARD_DISABLED_IN_PRODUCTION"
        for w in warnings
        if isinstance(w, dict)
    )
    assert any(w.get("code") == "PRODUCTION_NON_PERSISTENT_STORES_ACTIVE" for w in warnings if isinstance(w, dict))


def test_health_endpoint_reports_python_version_warning(monkeypatch):
    monkeypatch.setattr(runtime_state, "runtime_sys", SimpleNamespace(version_info=(3, 14, 0, "final", 0)))

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    warnings = body["diagnostics"].get("configuration_warnings") or []
    assert any(
        w.get("code") == "PYTHON_VERSION_MAY_BE_UNSUPPORTED_BY_CHROMADB" for w in warnings if isinstance(w, dict)
    )


def test_health_endpoint_reports_dispatcher_worker_heartbeat_metrics(monkeypatch):
    monkeypatch.setattr(config.job_runner, "mode", "redis_queue")
    monkeypatch.setattr(config.job_runner, "redis_worker_heartbeat_policy_mode", "warn")
    monkeypatch.setattr(
        runtime_state,
        "JOB_RUNNER",
        type(
            "_Runner",
            (),
            {
                "diagnostics": staticmethod(
                    lambda: {
                        "backend": "redis",
                        "consumer_enabled": False,
                        "running": False,
                        "redis_available": True,
                        "queue_size": 0,
                        "worker_heartbeat": {
                            "present": True,
                            "healthy": True,
                            "age_seconds": 0.4,
                            "source": "worker_process",
                        },
                    }
                )
            },
        )(),
    )

    response = client.get("/health")
    assert response.status_code == 200
    body = response.json()
    diagnostics = body["diagnostics"]
    assert diagnostics["job_runner"]["dispatcher_worker_heartbeat_policy"]["mode"] == "warn"
    heartbeat = diagnostics["job_runner"]["dispatcher_worker_heartbeat"]
    assert isinstance(heartbeat, dict)
    assert heartbeat["healthy"] is True
    assert heartbeat["source"] == "worker_process"
    assert float(heartbeat["age_seconds"]) >= 0.0


def test_ready_endpoint_reports_chroma_port_conflict_warning(monkeypatch):
    monkeypatch.setattr(vector_store, "_chroma_host", "127.0.0.1")
    monkeypatch.setattr(vector_store, "_chroma_port", 8000)

    response = client.get("/ready")
    assert response.status_code == 200
    body = response.json()
    warnings = body["checks"].get("configuration_warnings") or []
    assert any(w.get("code") == "CHROMA_PORT_MAY_CONFLICT_WITH_API_DEFAULT" for w in warnings if isinstance(w, dict))


def test_ready_endpoint_reports_tenant_authz_without_allowlist_warning(monkeypatch):
    monkeypatch.setenv("GRANTFLOW_TENANT_AUTHZ_ENABLED", "true")
    monkeypatch.delenv("GRANTFLOW_ALLOWED_TENANTS", raising=False)
    monkeypatch.delenv("AIDGRAPH_ALLOWED_TENANTS", raising=False)

    response = client.get("/ready")
    assert response.status_code == 200
    body = response.json()
    warnings = body["checks"].get("configuration_warnings") or []
    assert any(w.get("code") == "TENANT_AUTHZ_ENABLED_WITHOUT_ALLOWLIST" for w in warnings if isinstance(w, dict))


def test_ready_endpoint_reports_default_tenant_not_in_allowlist_warning(monkeypatch):
    monkeypatch.setenv("GRANTFLOW_TENANT_AUTHZ_ENABLED", "true")
    monkeypatch.setenv("GRANTFLOW_ALLOWED_TENANTS", "tenant_alpha")
    monkeypatch.setenv("GRANTFLOW_DEFAULT_TENANT", "tenant_beta")

    response = client.get("/ready")
    assert response.status_code == 200
    body = response.json()
    warnings = body["checks"].get("configuration_warnings") or []
    assert any(w.get("code") == "TENANT_DEFAULT_NOT_IN_ALLOWLIST" for w in warnings if isinstance(w, dict))


def test_ready_endpoint_reports_production_persistent_store_warnings(monkeypatch):
    class FakeJobStore:
        db_path = None

    class FakeHitlManager:
        _use_sqlite = False

    class FakeIngestAuditStore:
        db_path = None

    monkeypatch.setenv("GRANTFLOW_ENV", "production")
    monkeypatch.setenv("GRANTFLOW_REQUIRE_PERSISTENT_STORES_ON_STARTUP", "false")
    monkeypatch.setattr(runtime_state, "JOB_STORE", FakeJobStore())
    monkeypatch.setattr(runtime_state, "hitl_manager", FakeHitlManager())
    monkeypatch.setattr(runtime_state, "INGEST_AUDIT_STORE", FakeIngestAuditStore())

    response = client.get("/ready")
    assert response.status_code == 200
    body = response.json()
    warnings = body["checks"].get("configuration_warnings") or []
    assert any(
        w.get("code") == "PERSISTENT_STORE_STARTUP_GUARD_DISABLED_IN_PRODUCTION"
        for w in warnings
        if isinstance(w, dict)
    )
    assert any(w.get("code") == "PRODUCTION_NON_PERSISTENT_STORES_ACTIVE" for w in warnings if isinstance(w, dict))


def test_ready_endpoint_reports_python_version_warning(monkeypatch):
    monkeypatch.setattr(runtime_state, "runtime_sys", SimpleNamespace(version_info=(3, 14, 0, "final", 0)))

    response = client.get("/ready")
    assert response.status_code == 200
    body = response.json()
    warnings = body["checks"].get("configuration_warnings") or []
    assert any(
        w.get("code") == "PYTHON_VERSION_MAY_BE_UNSUPPORTED_BY_CHROMADB" for w in warnings if isinstance(w, dict)
    )
