"""Push retry job outcome classification."""

from datetime import datetime, timezone
from types import SimpleNamespace

from server.background.retry_runner import apply_push_retry_outcome


def _job(**kwargs):
    defaults = {
        "retry_count": 1,
        "max_retries": 3,
        "status": "pending",
        "last_error": None,
        "next_retry_at": None,
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


def test_success_marks_completed():
    job = _job(retry_count=1)
    apply_push_retry_outcome(
        job,
        {"total": 1, "completed": 1, "failed": 0, "cancelled": 0},
        now=datetime.now(timezone.utc),
    )
    assert job.status == "completed"


def test_cancelled_only_marks_failed_not_pending():
    job = _job(retry_count=1)
    apply_push_retry_outcome(
        job,
        {"total": 1, "completed": 0, "failed": 0, "cancelled": 1},
        now=datetime.now(timezone.utc),
    )
    assert job.status == "failed"
    assert "取消" in (job.last_error or "")


def test_sync_error_schedules_backoff_when_under_max():
    job = _job(retry_count=1, max_retries=3)
    now = datetime.now(timezone.utc)
    apply_push_retry_outcome(job, {"error": "no source", "total": 0}, now=now)
    assert job.status == "pending"
    assert job.next_retry_at is not None
    assert job.next_retry_at > now


def test_exhausted_retries_marks_failed():
    job = _job(retry_count=3, max_retries=3)
    apply_push_retry_outcome(
        job,
        {"total": 1, "completed": 0, "failed": 1, "cancelled": 0},
        now=datetime.now(timezone.utc),
    )
    assert job.status == "failed"


def test_running_job_returns_to_pending_after_retryable_failure():
    job = _job(retry_count=1, status="running")
    now = datetime.now(timezone.utc)
    apply_push_retry_outcome(
        job,
        {"total": 1, "completed": 0, "failed": 1, "cancelled": 0},
        now=now,
    )
    assert job.status == "pending"
    assert job.next_retry_at > now
