from grantflow.swarm.critic_rules import evaluate_rule_based_critic
from grantflow.tests.critic_rules_grounding_quality_helpers import state_with_updates


def test_rule_based_critic_warns_when_some_toc_text_is_placeholder():
    state = state_with_updates(
        toc_draft={
            "toc": {
                "project_goal": "Improve AI service delivery in civil service.",
                "objectives": [
                    {"title": "Objective 1", "description": "TBD"},
                    {"title": "Objective 2", "description": "Adopt risk-based deployment process."},
                ],
            }
        },
        logframe_draft={"indicators": [{"indicator_id": "IND_001", "baseline": "0", "target": "60"}]},
        citations=[
            {
                "stage": "architect",
                "used_for": "toc_claim",
                "statement_path": "toc.project_goal",
                "citation_type": "rag_claim_support",
                "citation_confidence": 0.8,
                "confidence_threshold": 0.4,
                "doc_id": "doc-1",
                "source": "policy.pdf",
                "page": 1,
                "chunk": 0,
            },
            {"stage": "mel", "used_for": "IND_001", "label": "doc"},
        ],
    )

    report = evaluate_rule_based_critic(state)
    checks = [c.model_dump() if hasattr(c, "model_dump") else c.dict() for c in report.checks]
    flaws = [f.model_dump() if hasattr(f, "model_dump") else f.dict() for f in report.fatal_flaws]

    assert any(c["code"] == "TOC_TEXT_COMPLETENESS" and c["status"] == "warn" for c in checks)
    assert any(f["code"] == "TOC_PLACEHOLDER_CONTENT" for f in flaws)


def test_rule_based_critic_fails_when_toc_text_is_placeholder_dominant():
    state = state_with_updates(
        toc_draft={
            "toc": {
                "project_goal": "TBD",
                "objectives": [
                    {"title": "TODO", "description": "placeholder"},
                    {"title": "Objective 2", "description": "to be determined"},
                ],
            }
        },
        logframe_draft={"indicators": [{"indicator_id": "IND_001", "baseline": "0", "target": "60"}]},
        citations=[
            {
                "stage": "architect",
                "used_for": "toc_claim",
                "statement_path": "toc.project_goal",
                "citation_type": "rag_claim_support",
                "citation_confidence": 0.8,
                "confidence_threshold": 0.4,
                "doc_id": "doc-1",
                "source": "policy.pdf",
                "page": 1,
                "chunk": 0,
            },
            {"stage": "mel", "used_for": "IND_001", "label": "doc"},
        ],
    )

    report = evaluate_rule_based_critic(state)
    checks = [c.model_dump() if hasattr(c, "model_dump") else c.dict() for c in report.checks]
    flaws = [f.model_dump() if hasattr(f, "model_dump") else f.dict() for f in report.fatal_flaws]

    assert any(c["code"] == "TOC_TEXT_COMPLETENESS" and c["status"] == "fail" for c in checks)
    assert any(f["code"] == "TOC_PLACEHOLDER_CONTENT_CRITICAL" for f in flaws)


def test_rule_based_critic_warns_when_toc_narrative_is_boilerplate_repeated():
    repeated_description = (
        "Program implementation delivers measurable governance improvements through repeatable capacity cycles "
        "and standardized compliance checkpoints across institutions."
    )
    state = state_with_updates(
        toc_draft={
            "toc": {
                "project_goal": "Improve accountability and service quality across ministries.",
                "development_objectives": [
                    {"do_id": "DO1", "description": repeated_description},
                    {"do_id": "DO2", "description": repeated_description},
                    {"do_id": "DO3", "description": repeated_description},
                ],
            }
        },
        logframe_draft={"indicators": [{"indicator_id": "IND_001", "baseline": "0", "target": "60"}]},
        citations=[
            {"stage": "architect", "used_for": "toc_claim", "statement_path": "toc.project_goal", "label": "doc"},
            {"stage": "mel", "used_for": "IND_001", "label": "doc"},
        ],
    )

    report = evaluate_rule_based_critic(state)
    checks = [c.model_dump() if hasattr(c, "model_dump") else c.dict() for c in report.checks]
    flaws = [f.model_dump() if hasattr(f, "model_dump") else f.dict() for f in report.fatal_flaws]

    assert any(c["code"] == "TOC_NARRATIVE_DIVERSITY" and c["status"] == "warn" for c in checks)
    assert any(f["code"] == "TOC_BOILERPLATE_REPETITION" for f in flaws)


def test_rule_based_critic_passes_toc_narrative_diversity_when_descriptions_are_distinct():
    state = state_with_updates(
        toc_draft={
            "toc": {
                "project_goal": "Improve accountability and service quality across ministries.",
                "development_objectives": [
                    {
                        "do_id": "DO1",
                        "description": "Civil service units adopt common AI governance standards with enforceable review gates.",
                    },
                    {
                        "do_id": "DO2",
                        "description": "Training programs build procurement and risk-audit skills for department focal points.",
                    },
                    {
                        "do_id": "DO3",
                        "description": "Interagency reporting mechanisms publish quarterly transparency and incident response metrics.",
                    },
                ],
            }
        },
        logframe_draft={"indicators": [{"indicator_id": "IND_001", "baseline": "0", "target": "60"}]},
        citations=[
            {"stage": "architect", "used_for": "toc_claim", "statement_path": "toc.project_goal", "label": "doc"},
            {"stage": "mel", "used_for": "IND_001", "label": "doc"},
        ],
    )

    report = evaluate_rule_based_critic(state)
    checks = [c.model_dump() if hasattr(c, "model_dump") else c.dict() for c in report.checks]
    flaws = [f.model_dump() if hasattr(f, "model_dump") else f.dict() for f in report.fatal_flaws]

    assert any(c["code"] == "TOC_NARRATIVE_DIVERSITY" and c["status"] == "pass" for c in checks)
    assert not any(f["code"] == "TOC_BOILERPLATE_REPETITION" for f in flaws)
