from collections.abc import Mapping
from typing import Any

from fastapi.testclient import TestClient

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

API_KEY = "test-secret"
AUTH_HEADERS = {"X-API-Key": API_KEY}
client = TestClient(app)


def enable_read_auth(monkeypatch) -> None:
    monkeypatch.setenv("GRANTFLOW_API_KEY", API_KEY)
    monkeypatch.setenv("GRANTFLOW_REQUIRE_AUTH_FOR_READS", "true")


def create_generated_job() -> str:
    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {"project": "Health Systems", "country": "Kenya"},
            "llm_mode": False,
            "hitl_enabled": False,
        },
        headers=AUTH_HEADERS,
    )
    assert response.status_code == 200
    return str(response.json()["job_id"])


def assert_auth_pair(
    method: str,
    path: str,
    *,
    json: Mapping[str, Any] | None = None,
) -> Any:
    request = getattr(client, method)
    if json is None:
        unauth = request(path)
        auth = request(path, headers=AUTH_HEADERS)
    else:
        unauth = request(path, json=json)
        auth = request(path, json=json, headers=AUTH_HEADERS)
    assert unauth.status_code == 401
    assert auth.status_code == 200
    return auth


class QueueAdminRunnerStub:
    def worker_heartbeat_status(self):
        return {
            "key": "grantflow:jobs:worker_heartbeat",
            "ttl_seconds": 45.0,
            "present": True,
            "healthy": True,
            "age_seconds": 0.2,
            "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": 0,
            "items": [],
        }

    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": 0,
            "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": 0,
            "dead_letter_queue_size": 0,
        }


def install_queue_admin_stub(monkeypatch) -> None:
    monkeypatch.setattr(config.job_runner, "mode", "redis_queue")
    monkeypatch.setattr(runtime_state, "JOB_RUNNER", QueueAdminRunnerStub())
