from grantflow.api import runtime_state
from grantflow.core.config import config

from grantflow.tests.queue_dispatch_helpers import client


def test_dead_letter_queue_endpoints_require_redis_queue_mode(monkeypatch):
    monkeypatch.setattr(config.job_runner, "mode", "background_tasks")

    heartbeat_resp = client.get("/queue/worker-heartbeat")
    assert heartbeat_resp.status_code == 409
    assert "redis_queue" in str(heartbeat_resp.json()["detail"])

    list_resp = client.get("/queue/dead-letter")
    assert list_resp.status_code == 409
    assert "redis_queue" in str(list_resp.json()["detail"])

    export_resp = client.get("/queue/dead-letter/export")
    assert export_resp.status_code == 409
    assert "redis_queue" in str(export_resp.json()["detail"])

    requeue_resp = client.post("/queue/dead-letter/requeue")
    assert requeue_resp.status_code == 409
    assert "redis_queue" in str(requeue_resp.json()["detail"])

    purge_resp = client.delete("/queue/dead-letter")
    assert purge_resp.status_code == 409
    assert "redis_queue" in str(purge_resp.json()["detail"])


def test_dead_letter_queue_endpoints_use_runner_in_redis_mode(monkeypatch):
    class _StubRunner:
        consumer_enabled = False

        def worker_heartbeat_status(self):
            return {
                "key": "grantflow:jobs:worker_heartbeat",
                "ttl_seconds": 45.0,
                "present": True,
                "healthy": True,
                "age_seconds": 0.5,
                "source": "worker_process",
            }

        def list_dead_letters(self, limit: int = 50):
            return {
                "mode": "redis_queue",
                "queue_name": "grantflow:jobs",
                "dead_letter_queue_name": "grantflow:jobs:dead",
                "dead_letter_queue_size": 1,
                "items": [{"index": 0, "task_name": "grantflow.api.app:_run_pipeline_to_completion_by_job_id"}],
            }

        def requeue_dead_letters(self, limit: int = 10, reset_attempts: bool = True):
            _ = reset_attempts
            return {
                "mode": "redis_queue",
                "queue_name": "grantflow:jobs",
                "dead_letter_queue_name": "grantflow:jobs:dead",
                "requested_count": int(limit),
                "affected_count": 1,
                "skipped_count": 0,
                "dead_letter_queue_size": 0,
            }

        def purge_dead_letters(self, limit: int = 100):
            return {
                "mode": "redis_queue",
                "queue_name": "grantflow:jobs",
                "dead_letter_queue_name": "grantflow:jobs:dead",
                "requested_count": int(limit),
                "affected_count": 1,
                "dead_letter_queue_size": 0,
            }

    monkeypatch.setattr(config.job_runner, "mode", "redis_queue")
    monkeypatch.setattr(runtime_state, "JOB_RUNNER", _StubRunner())

    heartbeat = client.get("/queue/worker-heartbeat")
    assert heartbeat.status_code == 200
    heartbeat_body = heartbeat.json()
    assert heartbeat_body["mode"] == "redis_queue"
    assert heartbeat_body["policy"]["mode"] in {"off", "warn", "strict"}
    assert heartbeat_body["consumer_enabled"] is False
    assert heartbeat_body["heartbeat"]["healthy"] is True

    listed = client.get("/queue/dead-letter", params={"limit": 5})
    assert listed.status_code == 200
    listed_body = listed.json()
    assert listed_body["mode"] == "redis_queue"
    assert listed_body["dead_letter_queue_size"] == 1
    assert listed_body["items"]

    export_json = client.get("/queue/dead-letter/export", params={"limit": 5, "format": "json"})
    assert export_json.status_code == 200
    assert "application/json" in (export_json.headers.get("content-type") or "")
    assert "grantflow_queue_dead_letter" in (export_json.headers.get("content-disposition") or "")

    export_csv = client.get("/queue/dead-letter/export", params={"limit": 5, "format": "csv"})
    assert export_csv.status_code == 200
    assert "text/csv" in (export_csv.headers.get("content-type") or "")
    assert "task_name" in export_csv.text

    requeue = client.post("/queue/dead-letter/requeue", params={"limit": 2, "reset_attempts": True})
    assert requeue.status_code == 200
    requeue_body = requeue.json()
    assert requeue_body["affected_count"] == 1
    assert requeue_body["requested_count"] == 2

    purge = client.delete("/queue/dead-letter", params={"limit": 3})
    assert purge.status_code == 200
    purge_body = purge.json()
    assert purge_body["affected_count"] == 1
    assert purge_body["requested_count"] == 3


def test_queue_worker_heartbeat_endpoint_falls_back_on_invalid_payload(monkeypatch):
    class _InvalidHeartbeatRunner:
        consumer_enabled = True

        def worker_heartbeat_status(self):
            return ["invalid"]

    monkeypatch.setattr(config.job_runner, "mode", "redis_queue")
    monkeypatch.setattr(runtime_state, "JOB_RUNNER", _InvalidHeartbeatRunner())

    response = client.get("/queue/worker-heartbeat")
    assert response.status_code == 200
    body = response.json()
    assert body["mode"] == "redis_queue"
    assert body["consumer_enabled"] is True
    assert body["heartbeat"]["present"] is False
    assert body["heartbeat"]["healthy"] is False
    assert body["heartbeat"]["error"] == "invalid_worker_heartbeat_payload"
