# grantflow/tests/test_integration_review_workflow_sla_hotspots.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_sla_hotspots_endpoints_filter_and_aggregate():
    job_id = "review-workflow-sla-hotspots-job-1"
    runtime_state.JOB_STORE.set(
        job_id,
        {
            "status": "done",
            "state": {
                "critic_notes": {
                    "fatal_flaws": [
                        {
                            "finding_id": "finding-h1",
                            "code": "TOC_SCHEMA_INVALID",
                            "severity": "high",
                            "section": "toc",
                            "status": "open",
                            "message": "ToC mismatch.",
                            "updated_at": "2026-02-27T14:00:00+00:00",
                            "due_at": "2026-02-27T08:00:00+00:00",
                            "sla_hours": 24,
                        },
                        {
                            "finding_id": "finding-h2",
                            "code": "MEL_BASELINE_MISSING",
                            "severity": "medium",
                            "section": "logframe",
                            "status": "acknowledged",
                            "message": "Baseline missing.",
                            "updated_at": "2026-02-27T14:30:00+00:00",
                            "due_at": "2026-02-26T08:00:00+00:00",
                            "sla_hours": 72,
                        },
                        {
                            "finding_id": "finding-h3",
                            "code": "CITATION_GAP",
                            "severity": "low",
                            "section": "general",
                            "status": "resolved",
                            "message": "Citation fixed.",
                            "updated_at": "2026-02-27T10:00:00+00:00",
                            "due_at": "2026-02-26T10:00:00+00:00",
                            "sla_hours": 72,
                        },
                    ]
                }
            },
            "review_comments": [
                {
                    "comment_id": "comment-h1",
                    "ts": "2026-02-27T13:00:00+00:00",
                    "section": "toc",
                    "status": "open",
                    "message": "Need stronger assumptions.",
                    "linked_finding_id": "finding-h1",
                    "due_at": "2026-02-27T09:00:00+00:00",
                    "sla_hours": 24,
                },
                {
                    "comment_id": "comment-h2",
                    "ts": "2026-02-27T13:05:00+00:00",
                    "section": "logframe",
                    "status": "open",
                    "message": "Indicator wording update pending.",
                    "linked_finding_id": "finding-h2",
                    "due_at": "2026-02-26T09:00:00+00:00",
                    "sla_hours": 72,
                },
                {
                    "comment_id": "comment-h3",
                    "ts": "2026-02-27T13:06:00+00:00",
                    "section": "general",
                    "status": "resolved",
                    "message": "Resolved by reviewer.",
                    "linked_finding_id": "finding-h3",
                    "due_at": "2026-02-26T11:00:00+00:00",
                    "sla_hours": 72,
                },
            ],
            "job_events": [
                {
                    "event_id": "rwf-sla-hotspots-1",
                    "ts": "2026-02-27T15:00:00+00:00",
                    "type": "critic_finding_status_changed",
                    "finding_id": "finding-h2",
                    "status": "acknowledged",
                    "section": "logframe",
                    "severity": "medium",
                }
            ],
        },
    )

    hotspots_resp = client.get(f"/status/{job_id}/review/workflow/sla/hotspots", params={"overdue_after_hours": 2})
    assert hotspots_resp.status_code == 200
    hotspots = hotspots_resp.json()
    assert hotspots["job_id"] == job_id
    assert hotspots["status"] == "done"
    assert hotspots["filters"]["overdue_after_hours"] == 2
    assert hotspots["filters"]["top_limit"] == 10
    assert hotspots["total_overdue_items"] == 4
    assert hotspots["hotspot_count"] == 4
    assert hotspots["top_overdue"][0]["id"] == "finding-h2"
    assert hotspots["hotspot_kind_counts"]["finding"] == 2
    assert hotspots["hotspot_kind_counts"]["comment"] == 2
    assert hotspots["hotspot_severity_counts"]["high"] == 2
    assert hotspots["hotspot_severity_counts"]["medium"] == 2

    kind_filtered = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots",
        params={"hotspot_kind": "comment", "overdue_after_hours": 2},
    )
    assert kind_filtered.status_code == 200
    kind_payload = kind_filtered.json()
    assert kind_payload["filters"]["hotspot_kind"] == "comment"
    assert kind_payload["total_overdue_items"] == 2
    assert kind_payload["hotspot_kind_counts"]["comment"] == 2

    severity_filtered = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots",
        params={"hotspot_severity": "high", "overdue_after_hours": 2},
    )
    assert severity_filtered.status_code == 200
    severity_payload = severity_filtered.json()
    assert severity_payload["filters"]["hotspot_severity"] == "high"
    assert severity_payload["total_overdue_items"] == 2
    assert all(str(item.get("severity") or "") == "high" for item in severity_payload["top_overdue"])

    min_overdue_filtered = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots",
        params={"min_overdue_hours": 31, "overdue_after_hours": 2},
    )
    assert min_overdue_filtered.status_code == 200
    min_overdue_payload = min_overdue_filtered.json()
    assert min_overdue_payload["filters"]["min_overdue_hours"] == 31.0
    assert min_overdue_payload["total_overdue_items"] == 1
    assert min_overdue_payload["top_overdue"][0]["id"] == "finding-h2"

    invalid_kind = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots",
        params={"hotspot_kind": "timeline", "overdue_after_hours": 2},
    )
    assert invalid_kind.status_code == 400

    trends_resp = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots/trends",
        params={"overdue_after_hours": 2},
    )
    assert trends_resp.status_code == 200
    trends = trends_resp.json()
    assert trends["job_id"] == job_id
    assert trends["status"] == "done"
    assert trends["hotspot_count_total"] == 4
    assert trends["bucket_count"] == 2
    assert trends["time_window_start"] == "2026-02-26"
    assert trends["time_window_end"] == "2026-02-27"
    assert trends["total_series"] == [
        {"bucket": "2026-02-26", "count": 2},
        {"bucket": "2026-02-27", "count": 2},
    ]
    assert trends["kind_series"]["finding"] == [
        {"bucket": "2026-02-26", "count": 1},
        {"bucket": "2026-02-27", "count": 1},
    ]
    assert trends["kind_series"]["comment"] == [
        {"bucket": "2026-02-26", "count": 1},
        {"bucket": "2026-02-27", "count": 1},
    ]

    trends_filtered = client.get(
        f"/status/{job_id}/review/workflow/sla/hotspots/trends",
        params={"hotspot_kind": "finding", "overdue_after_hours": 2},
    )
    assert trends_filtered.status_code == 200
    trends_filtered_payload = trends_filtered.json()
    assert trends_filtered_payload["filters"]["hotspot_kind"] == "finding"
    assert trends_filtered_payload["hotspot_count_total"] == 2
    assert trends_filtered_payload["bucket_count"] == 2
    assert trends_filtered_payload["total_series"] == [
        {"bucket": "2026-02-26", "count": 1},
        {"bucket": "2026-02-27", "count": 1},
    ]
