# grantflow/tests/test_integration_review_workflow_summary.py

from fastapi.testclient import TestClient


from grantflow.api import runtime_state

from grantflow.api.app import app

client = TestClient(app)


def test_status_review_workflow_endpoint_aggregates_findings_comments_and_timeline():
    job_id = "review-workflow-job-1"
    runtime_state.JOB_STORE.set(
        job_id,
        {
            "status": "done",
            "state": {
                "critic_notes": {
                    "fatal_flaws": [
                        {
                            "finding_id": "finding-1",
                            "code": "TOC_SCHEMA_INVALID",
                            "severity": "high",
                            "section": "toc",
                            "status": "resolved",
                            "message": "ToC schema mismatch.",
                            "resolved_at": "2026-02-27T10:12:00+00:00",
                        },
                        {
                            "finding_id": "finding-2",
                            "code": "MEL_BASELINE_MISSING",
                            "severity": "low",
                            "section": "logframe",
                            "status": "open",
                            "message": "Baseline is missing for one indicator.",
                        },
                    ]
                }
            },
            "review_comments": [
                {
                    "comment_id": "comment-1",
                    "ts": "2026-02-27T10:00:00+00:00",
                    "section": "toc",
                    "status": "resolved",
                    "message": "Reviewed and addressed in v2.",
                    "author": "reviewer-1",
                    "linked_finding_id": "finding-1",
                },
                {
                    "comment_id": "comment-2",
                    "ts": "2026-02-27T10:01:00+00:00",
                    "section": "general",
                    "status": "open",
                    "message": "Need sign-off from program manager.",
                    "author": "reviewer-2",
                    "linked_finding_id": "missing-finding",
                },
            ],
            "job_events": [
                {
                    "event_id": "rwf-1",
                    "ts": "2026-02-27T10:00:00+00:00",
                    "type": "review_comment_added",
                    "comment_id": "comment-1",
                    "section": "toc",
                    "author": "reviewer-1",
                },
                {
                    "event_id": "rwf-2",
                    "ts": "2026-02-27T10:05:00+00:00",
                    "type": "critic_finding_status_changed",
                    "finding_id": "finding-1",
                    "status": "acknowledged",
                    "section": "toc",
                    "severity": "high",
                    "actor": "qa-reviewer",
                },
                {
                    "event_id": "rwf-3",
                    "ts": "2026-02-27T10:10:00+00:00",
                    "type": "review_comment_status_changed",
                    "comment_id": "comment-1",
                    "status": "resolved",
                    "section": "toc",
                    "actor": "qa-reviewer",
                },
                {
                    "event_id": "rwf-4",
                    "ts": "2026-02-27T10:12:00+00:00",
                    "type": "critic_finding_status_changed",
                    "finding_id": "finding-1",
                    "status": "resolved",
                    "section": "toc",
                    "severity": "high",
                    "actor": "qa-reviewer",
                },
                {
                    "event_id": "rwf-ignore",
                    "ts": "2026-02-27T10:15:00+00:00",
                    "type": "status_changed",
                    "to_status": "done",
                },
            ],
        },
    )

    response = client.get(f"/status/{job_id}/review/workflow")
    assert response.status_code == 200
    body = response.json()
    assert body["job_id"] == job_id
    assert body["status"] == "done"
    assert body.get("filters", {}).get("event_type") is None
    assert body.get("filters", {}).get("finding_id") is None
    assert body.get("filters", {}).get("finding_code") is None
    assert body.get("filters", {}).get("finding_section") is None
    assert body.get("filters", {}).get("comment_status") is None
    assert body.get("filters", {}).get("workflow_state") is None
    assert body.get("filters", {}).get("overdue_after_hours") == 48
    assert len(body["findings"]) == 2
    assert len(body["comments"]) == 2

    summary = body["summary"]
    assert summary["finding_count"] == 2
    assert summary["comment_count"] == 2
    assert summary["linked_comment_count"] == 2
    assert summary["orphan_linked_comment_count"] == 1
    assert summary["open_finding_count"] == 1
    assert summary["acknowledged_finding_count"] == 0
    assert summary["resolved_finding_count"] == 1
    assert summary["pending_finding_count"] == 1
    assert summary["overdue_finding_count"] == 0
    assert summary["open_comment_count"] == 1
    assert summary["resolved_comment_count"] == 1
    assert summary["pending_comment_count"] == 1
    assert summary["overdue_comment_count"] == 0
    assert summary["finding_status_counts"]["open"] == 1
    assert summary["finding_status_counts"]["resolved"] == 1
    assert summary["finding_severity_counts"]["high"] == 1
    assert summary["finding_severity_counts"]["low"] == 1
    assert summary["comment_status_counts"]["open"] == 1
    assert summary["comment_status_counts"]["resolved"] == 1
    assert summary["timeline_event_count"] == 4
    assert summary["last_activity_at"] == "2026-02-27T10:12:00+00:00"
    assert summary["throughput_summary"]["finding_ack_completed_count"] == 1
    assert summary["throughput_summary"]["finding_resolve_completed_count"] == 1
    assert summary["throughput_summary"]["comment_added_count"] == 1
    assert summary["throughput_summary"]["comment_resolve_completed_count"] == 1
    assert summary["queue_delta_summary"]["finding_ack_queue_count"] == 1
    assert summary["queue_delta_summary"]["finding_ack_net_delta"] == 0
    assert summary["queue_delta_summary"]["comment_ack_net_delta"] == 1

    timeline = body["timeline"]
    assert len(timeline) == 4
    assert timeline[0]["ts"] == "2026-02-27T10:12:00+00:00"
    assert timeline[-1]["ts"] == "2026-02-27T10:00:00+00:00"
    timeline_types = {row["type"] for row in timeline}
    assert timeline_types == {
        "critic_finding_status_changed",
        "review_comment_added",
        "review_comment_status_changed",
    }

    finding_filtered = client.get(f"/status/{job_id}/review/workflow", params={"finding_id": "finding-1"})
    assert finding_filtered.status_code == 200
    finding_filtered_body = finding_filtered.json()
    assert finding_filtered_body["filters"]["finding_id"] == "finding-1"
    assert len(finding_filtered_body["findings"]) == 1
    assert all((row.get("finding_id") or row.get("id")) == "finding-1" for row in finding_filtered_body["findings"])
    assert all(str(row.get("linked_finding_id") or "") == "finding-1" for row in finding_filtered_body["comments"])

    finding_code_filtered = client.get(
        f"/status/{job_id}/review/workflow",
        params={"finding_code": "mel_baseline_missing"},
    )
    assert finding_code_filtered.status_code == 200
    finding_code_filtered_body = finding_code_filtered.json()
    assert finding_code_filtered_body["filters"]["finding_code"] == "MEL_BASELINE_MISSING"
    assert {row["finding_id"] for row in finding_code_filtered_body["findings"]} == {"finding-2"}
    assert finding_code_filtered_body["comments"] == []
    assert finding_code_filtered_body["timeline"] == []

    finding_section_filtered = client.get(
        f"/status/{job_id}/review/workflow",
        params={"finding_section": "toc"},
    )
    assert finding_section_filtered.status_code == 200
    finding_section_filtered_body = finding_section_filtered.json()
    assert finding_section_filtered_body["filters"]["finding_section"] == "toc"
    assert {row["finding_id"] for row in finding_section_filtered_body["findings"]} == {"finding-1"}
    assert {row["comment_id"] for row in finding_section_filtered_body["comments"]} == {"comment-1"}
    assert finding_section_filtered_body["timeline"]
    assert all(
        str(row.get("section") or "").lower() == "toc"
        or str(row.get("finding_id") or "") == "finding-1"
        or str(row.get("comment_id") or "") == "comment-1"
        for row in finding_section_filtered_body["timeline"]
    )

    comment_section_only = client.get(
        f"/status/{job_id}/review/workflow",
        params={"finding_section": "general"},
    )
    assert comment_section_only.status_code == 200
    comment_section_only_body = comment_section_only.json()
    assert comment_section_only_body["filters"]["finding_section"] == "general"
    assert comment_section_only_body["findings"] == []
    assert {row["comment_id"] for row in comment_section_only_body["comments"]} == {"comment-2"}
    assert comment_section_only_body["timeline"] == []

    event_type_filtered = client.get(
        f"/status/{job_id}/review/workflow",
        params={"event_type": "review_comment_status_changed"},
    )
    assert event_type_filtered.status_code == 200
    event_type_filtered_body = event_type_filtered.json()
    assert event_type_filtered_body["filters"]["event_type"] == "review_comment_status_changed"
    assert event_type_filtered_body["timeline"]
    assert all(row["type"] == "review_comment_status_changed" for row in event_type_filtered_body["timeline"])

    comment_status_filtered = client.get(
        f"/status/{job_id}/review/workflow",
        params={"comment_status": "resolved"},
    )
    assert comment_status_filtered.status_code == 200
    comment_status_filtered_body = comment_status_filtered.json()
    assert comment_status_filtered_body["filters"]["comment_status"] == "resolved"
    assert len(comment_status_filtered_body["comments"]) == 1
    assert all(str(row.get("status") or "") == "resolved" for row in comment_status_filtered_body["comments"])
