import json
import time
from pathlib import Path

from armorer.tools.orchestrator import get_job_status, reconcile_job_state, start_install_agent_job


class _FakeStdout:
    def __iter__(self):
        yield "Installing openclaw...\n"
        yield "Provisioning complete\n"


class _FakePopen:
    def __init__(self, *args, **kwargs):
        self.stdout = _FakeStdout()
        self.pid = 99999

    def wait(self):
        return 0


def test_start_install_agent_job_writes_and_completes(monkeypatch, tmp_path):
    monkeypatch.setattr(Path, "home", lambda: tmp_path)
    monkeypatch.setattr("armorer.tools.orchestrator.subprocess.Popen", _FakePopen)

    result = start_install_agent_job("openclaw")

    assert result["ok"] is True
    job_id = result["job_id"]

    deadline = time.time() + 2
    status = {}
    while time.time() < deadline:
        status = get_job_status(job_id)
        if status.get("status") == "completed":
            break
        time.sleep(0.05)

    assert status["ok"] is True
    assert status["status"] == "completed"
    assert "Provisioning complete" in "\n".join(status.get("recent_output") or [])


def test_reconcile_job_state_marks_old_running_job_stale(monkeypatch, tmp_path):
    monkeypatch.setattr(Path, "home", lambda: tmp_path)
    jobs = tmp_path / ".armorer" / "jobs"
    jobs.mkdir(parents=True, exist_ok=True)
    path = jobs / "job-1.json"
    path.write_text(json.dumps({
        "job_id": "job-1",
        "status": "running",
        "phase": "running",
        "message": "Still running",
        "updated_at": time.time() - 500,
        "started_at": time.time() - 600,
        "worker_pid": None,
    }))

    data = reconcile_job_state("job-1", persist=True)

    assert data["status"] == "failed"
    assert data["phase"] == "stale"
    persisted = json.loads(path.read_text())
    assert persisted["status"] == "failed"


def test_reconcile_job_state_ignores_container_pid_liveness_and_uses_heartbeat(monkeypatch, tmp_path):
    monkeypatch.setattr(Path, "home", lambda: tmp_path)
    jobs = tmp_path / ".armorer" / "jobs"
    jobs.mkdir(parents=True, exist_ok=True)
    path = jobs / "job-2.json"
    path.write_text(json.dumps({
        "job_id": "job-2",
        "status": "running",
        "phase": "running",
        "message": "Still running",
        "updated_at": time.time() - 500,
        "heartbeat_at": time.time() - 500,
        "started_at": time.time() - 600,
        "worker_pid": 16,
    }))

    data = reconcile_job_state("job-2", persist=True)

    assert data["status"] == "failed"
    assert data["phase"] == "stale"
    persisted = json.loads(path.read_text())
    assert persisted["status"] == "failed"
