# grantflow/tests/test_integration_hitl_flows_checkpoint_guards.py

import time


from fastapi.testclient import TestClient


from grantflow.api import runtime_state

from grantflow.api.app import app

from grantflow.api.idempotency_store_facade import _get_job

from grantflow.api.review_service import _pause_for_hitl

from grantflow.tests.integration_helpers import drain_hitl_to_done, wait_for_terminal_status

client = TestClient(app)


def test_hitl_checkpoint_selection_logframe_only_flow():
    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {"project": "Education", "country": "Kenya"},
            "llm_mode": False,
            "hitl_enabled": True,
            "hitl_checkpoints": ["logframe"],
        },
    )
    assert response.status_code == 200
    job_id = response.json()["job_id"]

    status = wait_for_terminal_status(client, job_id)
    assert status["status"] == "pending_hitl"
    assert status["checkpoint_stage"] == "logframe"
    assert status["state"]["hitl_pending"] is True
    assert status["state"]["toc_draft"]
    assert status["state"]["logframe_draft"]

    cp_id = status["checkpoint_id"]
    approve = client.post(
        "/hitl/approve",
        json={"checkpoint_id": cp_id, "approved": True, "feedback": "Logframe approved"},
    )
    assert approve.status_code == 200

    resume = client.post(f"/resume/{job_id}", json={})
    assert resume.status_code == 200
    assert resume.json()["resuming_from"] == "critic"

    status = wait_for_terminal_status(client, job_id)
    if status["status"] != "done":
        status = drain_hitl_to_done(client, job_id, initial_status=status)
    assert status["status"] == "done"
    assert status["state"]["hitl_pending"] is False


def test_resume_requires_checkpoint_decision_before_running_again():
    response = client.post(
        "/generate",
        json={
            "donor_id": "usaid",
            "input_context": {"project": "Education", "country": "Kenya"},
            "llm_mode": False,
            "hitl_enabled": True,
        },
    )
    assert response.status_code == 200
    job_id = response.json()["job_id"]

    status = wait_for_terminal_status(client, job_id)
    assert status["status"] == "pending_hitl"
    assert status["checkpoint_stage"] == "toc"

    resume = client.post(f"/resume/{job_id}", json={})
    assert resume.status_code == 409
    assert resume.json()["detail"]["code"] == "checkpoint_pending"


def test_resume_rejects_canceled_checkpoint():
    checkpoint_id = runtime_state.hitl_manager.create_checkpoint(
        stage="toc",
        state={"donor_id": "usaid", "input_context": {"project": "Canceled checkpoint", "country": "Kenya"}},
        donor_id="usaid",
    )
    assert runtime_state.hitl_manager.cancel(checkpoint_id, "Canceled externally")

    job_id = f"resume-canceled-checkpoint-{int(time.time() * 1_000_000)}"
    runtime_state.JOB_STORE.set(
        job_id,
        {
            "status": "pending_hitl",
            "state": {
                "donor_id": "usaid",
                "input_context": {"project": "Canceled checkpoint", "country": "Kenya"},
                "hitl_pending": True,
            },
            "hitl_enabled": True,
            "checkpoint_id": checkpoint_id,
            "checkpoint_stage": "toc",
            "resume_from": "mel",
        },
    )

    resume = client.post(f"/resume/{job_id}", json={})
    assert resume.status_code == 409
    assert "approved or rejected" in str(resume.json().get("detail") or "")


def test_hitl_approve_reject_conflict_after_finalized_checkpoint():
    checkpoint_id = runtime_state.hitl_manager.create_checkpoint(
        stage="toc",
        state={"donor_id": "usaid", "input_context": {"project": "Decision conflict", "country": "Kenya"}},
        donor_id="usaid",
    )

    first = client.post(
        "/hitl/approve",
        json={"checkpoint_id": checkpoint_id, "approved": True, "feedback": "Looks good"},
    )
    assert first.status_code == 200
    assert first.json()["status"] == "approved"

    conflict = client.post(
        "/hitl/approve",
        json={"checkpoint_id": checkpoint_id, "approved": False, "feedback": "Actually reject"},
    )
    assert conflict.status_code == 409
    assert "already finalized" in str(conflict.json().get("detail") or "")


def test_pause_for_hitl_replaces_stale_stage_checkpoint_reference():
    stale_checkpoint_id = runtime_state.hitl_manager.create_checkpoint(
        stage="logframe",
        state={"donor_id": "usaid", "input_context": {"project": "Stale checkpoint", "country": "Kenya"}},
        donor_id="usaid",
    )

    job_id = f"pause-stale-checkpoint-{int(time.time() * 1_000_000)}"
    state = {
        "donor_id": "usaid",
        "input_context": {"project": "Stale checkpoint", "country": "Kenya"},
        "hitl_enabled": True,
        "hitl_pending": True,
        "hitl_checkpoint_id": stale_checkpoint_id,
    }
    _pause_for_hitl(job_id, state, stage="toc", resume_from="mel")

    job = _get_job(job_id)
    assert job is not None
    assert job["status"] == "pending_hitl"
    assert job["checkpoint_stage"] == "toc"
    assert job["checkpoint_id"] != stale_checkpoint_id

    stale = runtime_state.hitl_manager.get_checkpoint(stale_checkpoint_id)
    assert stale is not None
    stale_status = getattr(stale.get("status"), "value", stale.get("status"))
    assert stale_status == "canceled"
