# grantflow/tests/test_integration_preflight_readiness.py

from fastapi.testclient import TestClient

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

client = TestClient(app)


def test_generate_preflight_reports_high_risk_when_namespace_empty():
    runtime_state.INGEST_AUDIT_STORE.clear()

    response = client.post("/generate/preflight", json={"donor_id": "usaid"})
    assert response.status_code == 200
    body = response.json()
    assert body["donor_id"] == "usaid"
    assert isinstance(body.get("retrieval_query_terms"), list)
    assert "development objectives" in body.get("retrieval_query_terms")
    assert body["namespace_empty"] is True
    assert body["risk_level"] == "high"
    assert body["grounding_risk_level"] == "high"
    grounding_policy = body.get("grounding_policy") or {}
    assert grounding_policy["mode"] in {"warn", "strict", "off"}
    assert grounding_policy["risk_level"] == "high"
    assert grounding_policy["go_ahead"] in {True, False}
    assert isinstance(grounding_policy.get("reasons"), list)
    thresholds = grounding_policy.get("thresholds") or {}
    assert 0.0 <= float(thresholds.get("high_risk_coverage_threshold") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("medium_risk_coverage_threshold") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("high_risk_depth_coverage_threshold") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("medium_risk_depth_coverage_threshold") or 0.0) <= 1.0
    assert float(thresholds.get("medium_risk_coverage_threshold") or 0.0) >= float(
        thresholds.get("high_risk_coverage_threshold") or 0.0
    )
    assert float(thresholds.get("medium_risk_depth_coverage_threshold") or 0.0) >= float(
        thresholds.get("high_risk_depth_coverage_threshold") or 0.0
    )
    assert int(thresholds.get("min_uploads") or 0) >= 1
    assert 0.0 <= float(thresholds.get("min_key_claim_coverage_rate") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("max_fallback_claim_ratio") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("max_traceability_gap_rate") or 0.0) <= 1.0
    assert 0.0 <= float(thresholds.get("min_threshold_hit_rate") or 0.0) <= 1.0
    architect_claims = body.get("architect_claims") or {}
    assert isinstance(architect_claims, dict)
    assert architect_claims.get("available") is False
    assert architect_claims.get("reason") == "input_context_missing"
    assert isinstance(body.get("doc_family_min_uploads"), dict)
    assert isinstance(body.get("depth_ready_doc_families"), list)
    assert isinstance(body.get("depth_gap_doc_families"), list)
    assert body.get("depth_ready_count") == 0
    assert body.get("depth_gap_count") == int(body.get("expected_count") or 0)
    assert body.get("depth_coverage_rate") == 0.0


def test_generate_preflight_accepts_architect_rag_toggle():
    runtime_state.INGEST_AUDIT_STORE.clear()

    response = client.post(
        "/generate/preflight",
        json={"donor_id": "usaid", "architect_rag_enabled": False},
    )
    assert response.status_code == 200
    body = response.json()
    assert body["architect_rag_enabled"] is False
    architect_claims = body.get("architect_claims") or {}
    assert architect_claims.get("retrieval_expected") is False


def test_generate_preflight_reports_depth_coverage_warning_when_family_min_not_met():
    runtime_state.INGEST_AUDIT_STORE.clear()
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "pref-depth-1",
            "ts": "2026-03-03T10:00:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 10},
        }
    )
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "pref-depth-2",
            "ts": "2026-03-03T10:05:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "country.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "country_context", "source_type": "country_context"},
            "result": {"chunks_ingested": 8},
        }
    )

    response = client.post("/generate/preflight", json={"donor_id": "usaid"})
    assert response.status_code == 200
    body = response.json()
    assert body["donor_id"] == "usaid"
    assert body["namespace_empty"] is False
    assert body["coverage_rate"] == 0.6667
    assert body["depth_ready_count"] == 1
    assert body["depth_gap_count"] == 2
    assert body["depth_coverage_rate"] == 0.3333
    warnings = body.get("warnings") or []
    warning_codes = {str(row.get("code") or "") for row in warnings if isinstance(row, dict)}
    assert "LOW_DOC_DEPTH_COVERAGE" in warning_codes
    grounding_policy = body.get("grounding_policy") or {}
    assert grounding_policy["risk_level"] in {"medium", "high"}
    assert "depth_coverage_below_medium_threshold" in (grounding_policy.get("reasons") or [])


def test_ingest_readiness_reports_preflight_payload_and_expected_families_override():
    runtime_state.INGEST_AUDIT_STORE.clear()
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-read-1",
            "ts": "2026-03-03T10:00:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201-a.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 7},
        }
    )
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-read-2",
            "ts": "2026-03-03T10:01:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201-b.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 6},
        }
    )
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-read-3",
            "ts": "2026-03-03T10:02:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "country.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "country_context", "source_type": "country_context"},
            "result": {"chunks_ingested": 5},
        }
    )

    response = client.post(
        "/ingest/readiness",
        json={
            "donor_id": "usaid",
            "expected_doc_families": ["donor_policy", "country_context"],
            "input_context": {"project": "AI training", "country": "Kazakhstan"},
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["donor_id"] == "usaid"
    assert isinstance(body.get("retrieval_query_terms"), list)
    assert "development objectives" in body.get("retrieval_query_terms")
    assert body["expected_doc_families"] == ["donor_policy", "country_context"]
    assert body["present_doc_families"] == ["donor_policy", "country_context"]
    assert body["missing_doc_families"] == []
    assert body["coverage_rate"] == 1.0
    assert body["depth_coverage_rate"] == 1.0
    assert body["risk_level"] in {"none", "low"}
    assert body["namespace_empty"] is False
    claims = body.get("architect_claims") or {}
    assert claims.get("available") is True


def test_ingest_readiness_emits_missing_doc_families_and_weak_corpus_coverage_reasons():
    runtime_state.INGEST_AUDIT_STORE.clear()
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-reason-1",
            "ts": "2026-03-03T10:00:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201-a.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 7},
        }
    )

    response = client.post(
        "/ingest/readiness",
        json={
            "donor_id": "usaid",
            "expected_doc_families": ["donor_policy", "country_context"],
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert "country_context" in (body.get("missing_doc_families") or [])
    assert body.get("blocking_reason_flags", {}).get("missing_doc_families") is True
    assert body.get("blocking_reason_flags", {}).get("weak_corpus_coverage") is True
    assert "missing_doc_families" in (body.get("blocking_reasons") or [])
    assert "weak_corpus_coverage" in (body.get("blocking_reasons") or [])


def test_ingest_readiness_emits_donor_mismatch_reason():
    runtime_state.INGEST_AUDIT_STORE.clear()
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-reason-2",
            "ts": "2026-03-03T10:00:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201-a.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 7},
        }
    )

    response = client.post(
        "/ingest/readiness",
        json={
            "donor_id": "usaid",
            "expected_doc_families": ["donor_policy"],
            "client_metadata": {"rag_readiness": {"donor_id": "unicef"}},
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body.get("blocking_reason_flags", {}).get("donor_mismatch") is True
    assert "donor_mismatch" in (body.get("blocking_reasons") or [])


def test_ingest_readiness_emits_stale_ingest_artifacts_reason(monkeypatch):
    runtime_state.INGEST_AUDIT_STORE.clear()
    runtime_state.INGEST_AUDIT_STORE.append(
        {
            "event_id": "ing-reason-3",
            "ts": "2026-03-03T10:00:00+00:00",
            "donor_id": "usaid",
            "tenant_id": None,
            "namespace": "usaid_ads201",
            "filename": "ads201-a.pdf",
            "content_type": "application/pdf",
            "metadata": {"doc_family": "donor_policy", "source_type": "donor_guidance"},
            "result": {"chunks_ingested": 7},
        }
    )
    monkeypatch.setattr(vector_store, "get_stats", lambda _namespace: {"document_count": 0})

    response = client.post(
        "/ingest/readiness",
        json={
            "donor_id": "usaid",
            "expected_doc_families": ["donor_policy"],
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body.get("vector_document_count") == 0
    assert body.get("blocking_reason_flags", {}).get("stale_ingest_artifacts") is True
    assert "stale_ingest_artifacts" in (body.get("blocking_reasons") or [])
    warning_codes = {str(row.get("code") or "") for row in (body.get("warnings") or []) if isinstance(row, dict)}
    assert "STALE_INGEST_ARTIFACTS" in warning_codes
