from grantflow.memory_bank.vector_store import vector_store
from grantflow.tests.review_traceability_helpers import client, generate_done_job


def test_status_includes_citations_traceability(monkeypatch):
    def fake_query(namespace, query_texts, n_results=5, where=None, top_k=None):
        return {
            "documents": [["Official indicator guidance excerpt"]],
            "ids": [["usaid_ads201_p12_c0"]],
            "distances": [[0.18]],
            "metadatas": [
                [
                    {
                        "source": "/tmp/usaid_guide.pdf",
                        "uploaded_filename": "usaid_guide.pdf",
                        "page": 12,
                        "page_start": 12,
                        "page_end": 12,
                        "chunk": 3,
                        "chunk_id": "usaid_ads201_p12_c0",
                        "indicator_id": "EG.3.2-1",
                        "citation": "USAID ADS 201 p.12",
                        "name": "Households with improved access",
                    }
                ]
            ],
        }

    monkeypatch.setattr(vector_store, "query", fake_query)
    job_id, status = generate_done_job({"project": "Water Sanitation", "country": "Kenya"})

    state = status["state"]
    citations = state.get("citations")
    assert isinstance(citations, list)
    assert citations

    mel_citations = [c for c in citations if c.get("stage") == "mel"]
    assert mel_citations
    citation = mel_citations[0]
    assert citation["citation_type"] == "rag_result"
    assert citation["namespace"] == "usaid_ads201"
    assert citation["namespace_normalized"] == "usaid_ads201"
    assert citation["source"] == "usaid_guide.pdf"
    assert citation["page"] == 12
    assert citation["chunk"] == 3
    assert citation["doc_id"] == "usaid_ads201_p12_c0"
    assert citation["chunk_id"] == "usaid_ads201_p12_c0"
    assert citation["used_for"] == "EG.3.2-1"
    assert citation["retrieval_rank"] == 1
    assert citation["retrieval_confidence"] > 0.0
    assert citation["retrieval_distance"] == 0.18
    assert "excerpt" in citation and citation["excerpt"]

    architect_citations = [c for c in citations if c.get("stage") == "architect"]
    assert architect_citations
    assert any(c.get("statement_path") for c in architect_citations)
    assert any(
        c.get("citation_type") in {"rag_claim_support", "rag_low_confidence", "fallback_namespace"}
        for c in architect_citations
    )
    assert any(c.get("doc_id") == "usaid_ads201_p12_c0" for c in architect_citations)
    assert all(c.get("namespace_normalized") == "usaid_ads201" for c in architect_citations)
    assert any(c.get("retrieval_rank") == 1 for c in architect_citations)
    for c in citations:
        source = str(c.get("source") or "")
        assert "grantflow_ingest_" not in source

    citations_response = client.get(f"/status/{job_id}/citations")
    assert citations_response.status_code == 200
    citations_body = citations_response.json()
    assert citations_body["job_id"] == job_id
    assert citations_body["status"] == "done"
    assert citations_body["citation_count"] >= 1
    assert isinstance(citations_body["citations"], list)
    assert isinstance(citations_body["architect_signal_summary"], dict)
    assert citations_body["citations"][0]["stage"]
    assert any("statement_path" in c for c in citations_body["citations"])
    assert any("citation_confidence" in c for c in citations_body["citations"])
    assert any("doc_id" in c for c in citations_body["citations"])
    assert any("retrieval_rank" in c for c in citations_body["citations"])
    assert citations_body["architect_signal_summary"]["architect_citation_count"] >= 1
    assert citations_body["architect_signal_summary"]["evidence_signal_count"] >= 1
    assert citations_body["architect_signal_summary"]["review_hint_count"] >= 1
    assert any(c.get("evidence_signal") for c in architect_citations)
    assert any(c.get("review_hint") for c in architect_citations)
    for c in citations_body["citations"]:
        if c.get("citation_confidence") is not None:
            assert 0.0 <= float(c["citation_confidence"]) <= 1.0
        if c.get("retrieval_confidence") is not None:
            assert 0.0 <= float(c["retrieval_confidence"]) <= 1.0
        if c.get("retrieval_distance") is not None:
            assert float(c["retrieval_distance"]) >= 0.0
