from grantflow.core.config import config
from grantflow.memory_bank.vector_store import vector_store
from grantflow.tests.integration_generation_grounding_helpers import (
    client,
    empty_vector_query,
    seed_grounding_ingest_audit_store,
    seeded_vector_query,
    stub_generate_preflight,
)
from grantflow.tests.integration_helpers import wait_for_terminal_status


def test_runtime_grounded_quality_gate_blocks_llm_when_non_retrieval_signals_dominate(monkeypatch):
    monkeypatch.setattr(config.graph, "grounding_gate_mode", "warn")
    monkeypatch.setattr(config.graph, "mel_grounding_policy_mode", "warn")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_mode", "strict")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_citations", 1)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_max_non_retrieval_citation_rate", 0.2)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_retrieval_grounded_citations", 1)
    stub_generate_preflight(monkeypatch)
    monkeypatch.setattr(vector_store, "query", empty_vector_query)

    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {"project": "Gov workflow modernization", "country": "Kenya"},
            "llm_mode": True,
            "hitl_enabled": False,
            "architect_rag_enabled": True,
        },
    )
    assert response.status_code == 200
    job_id = response.json()["job_id"]

    terminal = wait_for_terminal_status(client, job_id)
    assert terminal["status"] == "error"
    assert "Grounded quality gate (strict) blocked finalization" in str(terminal.get("error") or "")
    state = terminal.get("state") or {}
    gate = state.get("grounded_quality_gate") or {}
    assert gate.get("mode") == "strict"
    assert gate.get("applicable") is True
    assert gate.get("blocking") is True
    assert gate.get("passed") is False
    reasons = gate.get("reasons") if isinstance(gate.get("reasons"), list) else []
    assert "non_retrieval_citation_rate_above_max" in reasons
    reason_details = gate.get("reason_details") if isinstance(gate.get("reason_details"), list) else []
    assert reason_details
    detail_codes = {str(item.get("code") or "") for item in reason_details if isinstance(item, dict)}
    assert "non_retrieval_citation_rate_above_max" in detail_codes
    section_signals = gate.get("section_signals") if isinstance(gate.get("section_signals"), dict) else {}
    assert "toc" in section_signals
    assert "logframe" in section_signals
    flaws = (state.get("critic_notes") or {}).get("fatal_flaws") or []
    flaw_codes = {str(item.get("code") or "") for item in flaws if isinstance(item, dict)}
    assert "RUNTIME_GROUNDED_QUALITY_GATE_BLOCK" in flaw_codes
    runtime_gate_flaw = next(
        (
            item
            for item in flaws
            if isinstance(item, dict) and str(item.get("code") or "") == "RUNTIME_GROUNDED_QUALITY_GATE_BLOCK"
        ),
        {},
    )
    related_sections = runtime_gate_flaw.get("related_sections")
    assert isinstance(related_sections, list)
    assert any(section in {"toc", "logframe"} for section in related_sections)


def test_runtime_grounded_quality_gate_skips_when_architect_rag_disabled(monkeypatch):
    monkeypatch.setattr(config.graph, "grounding_gate_mode", "warn")
    monkeypatch.setattr(config.graph, "mel_grounding_policy_mode", "warn")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_mode", "strict")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_citations", 1)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_max_non_retrieval_citation_rate", 0.0)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_retrieval_grounded_citations", 99)
    stub_generate_preflight(monkeypatch)
    monkeypatch.setattr(vector_store, "query", empty_vector_query)

    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {"project": "Gov workflow modernization", "country": "Kenya"},
            "llm_mode": True,
            "hitl_enabled": False,
            "architect_rag_enabled": False,
        },
    )
    assert response.status_code == 200
    job_id = response.json()["job_id"]

    terminal = wait_for_terminal_status(client, job_id)
    assert terminal["status"] == "done"
    state = terminal.get("state") or {}
    gate = state.get("grounded_quality_gate") or {}
    assert gate.get("mode") == "strict"
    assert gate.get("applicable") is False
    assert gate.get("blocking") is False
    assert gate.get("passed") is True


def test_runtime_grounded_quality_gate_passes_with_seeded_corpus_grounded_llm(monkeypatch):
    monkeypatch.setattr(config.graph, "grounding_gate_mode", "warn")
    monkeypatch.setattr(config.graph, "mel_grounding_policy_mode", "warn")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_mode", "strict")
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_citations", 5)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_max_non_retrieval_citation_rate", 0.35)
    monkeypatch.setattr(config.graph, "runtime_grounded_quality_gate_min_retrieval_grounded_citations", 2)
    stub_generate_preflight(monkeypatch)
    seed_grounding_ingest_audit_store()
    monkeypatch.setattr(vector_store, "query", seeded_vector_query)

    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {
                "project": "AI civil service capability and governance modernization",
                "country": "Kazakhstan",
                "timeframe": "2026-2027",
            },
            "llm_mode": True,
            "hitl_enabled": False,
            "architect_rag_enabled": True,
        },
    )
    assert response.status_code == 200
    job_id = response.json()["job_id"]

    terminal = wait_for_terminal_status(client, job_id, timeout_s=5.0)
    assert terminal["status"] == "done"
    state = terminal.get("state") or {}
    gate = state.get("grounded_quality_gate") or {}
    assert gate.get("mode") == "strict"
    assert gate.get("applicable") is True
    assert gate.get("passed") is True
    assert gate.get("blocking") is False
    assert float(gate.get("non_retrieval_citation_rate") or 0.0) <= 0.35
    assert int(gate.get("retrieval_grounded_citation_count") or 0) >= 2
    section_signals = gate.get("section_signals") if isinstance(gate.get("section_signals"), dict) else {}
    assert "toc" in section_signals
    assert "logframe" in section_signals

    grounding_gate_response = client.get(f"/status/{job_id}/grounding-gate")
    assert grounding_gate_response.status_code == 200
    grounding_gate_body = grounding_gate_response.json()
    runtime_gate = grounding_gate_body.get("grounded_gate") or {}
    assert runtime_gate.get("passed") is True
    assert runtime_gate.get("blocking") is False
