"""Server batch zombie recovery and stuck detection helpers."""

import json
from datetime import datetime, timedelta, timezone

from server.domain.models import ServerBatchJob
from server.infrastructure.database.server_batch_job_repo import job_row_to_api
from server.infrastructure.redis import server_batch_store as sbs


def test_pending_server_ids():
    live = {
        "server_ids": [1, 2, 3],
        "results": {"1": {"server_id": 1, "success": True}},
    }
    assert sbs.pending_server_ids(live) == [2, 3]


def test_apply_pending_failures_marks_stuck():
    live = {"server_ids": [10], "results": {}}
    added = sbs.apply_pending_failures(
        live,
        server_ids=[10],
        error=sbs.STUCK_MESSAGE,
        auto_stuck=True,
        server_name_fallback="S10",
    )
    assert added == 1
    entry = live["results"]["10"]
    assert entry["success"] is False
    assert entry["auto_stuck"] is True
    assert entry["error"] == sbs.STUCK_MESSAGE


def test_finalize_status_after_pending_failures():
    live = {
        "server_ids": [1, 2],
        "results": {},
        "status": "running",
    }
    sbs.apply_pending_failures(
        live,
        server_ids=[1, 2],
        error=sbs.INTERRUPTED_MESSAGE,
    )
    status = sbs.finalize_status(live)
    assert status == "failed"
    assert live["status"] == "failed"


def test_is_stale_running_true_when_old_update():
    old = (datetime.now(timezone.utc) - timedelta(hours=2)).isoformat()
    live = {"status": "running", "updated_at": old}
    assert sbs.is_stale_running(live) is True


def test_is_stale_running_false_when_recent():
    recent = datetime.now(timezone.utc).isoformat()
    live = {"status": "running", "updated_at": recent}
    assert sbs.is_stale_running(live) is False


def test_live_from_mysql_row_rebuilds_results_map():
    row = ServerBatchJob(
        id=20,
        op="install-agent",
        label="批量安装 Agent",
        server_ids=json.dumps([290, 346]),
        status="running",
        results=json.dumps([
            {"server_id": 290, "server_name": "A", "success": True, "stdout": "ok", "error": ""},
        ]),
        operator="admin",
        started_at=datetime(2026, 6, 8, 10, 0, tzinfo=timezone.utc),
    )
    live = sbs.live_from_mysql_row(row)
    assert live["id"] == 20
    assert live["status"] == "running"
    assert sbs.pending_server_ids(live) == [346]
    api = job_row_to_api(row)
    assert api["remaining"] == 1
