"""tests/start_guard/test_cleanup_stale.py
stale lock 정리 테스트:
- test_cleanup_old_lock: 30분 이전 heartbeat lock → 삭제 + evidence 생성
- test_cleanup_fresh_lock: 최근 heartbeat lock은 보존
"""
from __future__ import annotations

import json
import os
import subprocess
from datetime import datetime, timedelta, timezone
from pathlib import Path

SCRIPT = Path("/home/jay/workspace/.worktrees/task-2454-dev4/scripts/start_task_guard.py")


def _run(args: list[str], cwd: Path, env: dict | None = None) -> subprocess.CompletedProcess:
    """스크립트 실행 헬퍼."""
    return subprocess.run(
        ["python3", str(SCRIPT)] + args,
        cwd=str(cwd),
        capture_output=True,
        text=True,
        timeout=30,
        env={**os.environ, **(env or {})},
    )


def _make_lock(locks_dir: Path, task_id: str, heartbeat_ts: str, pid: int = 99999) -> Path:
    """lock 파일 생성 헬퍼."""
    locks_dir.mkdir(parents=True, exist_ok=True)
    lock_path = locks_dir / f"{task_id}.lock"
    data = {
        "task_id": task_id,
        "pid": pid,
        "heartbeat_timestamp": heartbeat_ts,
        "bot": "dev9",
        "worktree": "/tmp/test",
        "branch": f"task/{task_id}-dev9",
        "started_at": heartbeat_ts,
    }
    lock_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    return lock_path


# ---------------------------------------------------------------------------
# test_cleanup_old_lock: stale lock (30분+) 삭제 + evidence 생성
# ---------------------------------------------------------------------------

def test_cleanup_old_lock(tmp_path: Path):
    """30분 초과 heartbeat lock이 삭제되고 evidence가 생성됨을 확인."""
    task_id = "task-stale-old"
    locks_dir = tmp_path / ".tasks" / "locks"

    # 60분 전 heartbeat
    old_ts = (datetime.now(timezone.utc) - timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%M:%SZ")
    lock_path = _make_lock(locks_dir, task_id, old_ts)
    assert lock_path.exists()

    result = _run(["--cleanup-stale"], cwd=tmp_path)
    assert result.returncode == 0, (
        f"--cleanup-stale 실패\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )

    # lock 파일 삭제 확인
    assert not lock_path.exists(), f"stale lock이 삭제되지 않음: {lock_path}"

    # evidence 파일 생성 확인
    evidence_path = tmp_path / "memory" / "events" / f"{task_id}.lock-cleanup.json"
    assert evidence_path.exists(), f"evidence 파일 미생성: {evidence_path}"

    # evidence 내용 검증
    evidence = json.loads(evidence_path.read_text(encoding="utf-8"))
    assert evidence["task_id"] == task_id
    assert "cleanup_reason" in evidence
    assert "cleanup_at" in evidence
    assert "elapsed_seconds" in evidence
    assert evidence["elapsed_seconds"] >= 3600 - 5  # 60분 - 허용 오차 5초


# ---------------------------------------------------------------------------
# test_cleanup_fresh_lock: 최근 heartbeat lock 보존
# ---------------------------------------------------------------------------

def test_cleanup_fresh_lock(tmp_path: Path):
    """최근(5분 전) heartbeat lock은 삭제되지 않고 보존됨을 확인."""
    task_id = "task-fresh-lock"
    locks_dir = tmp_path / ".tasks" / "locks"

    # 5분 전 heartbeat (30분 미만 → fresh)
    fresh_ts = (datetime.now(timezone.utc) - timedelta(minutes=5)).strftime("%Y-%m-%dT%H:%M:%SZ")
    lock_path = _make_lock(locks_dir, task_id, fresh_ts)
    assert lock_path.exists()

    result = _run(["--cleanup-stale"], cwd=tmp_path)
    assert result.returncode == 0, (
        f"--cleanup-stale 실패\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )

    # lock 파일이 보존되어야 함
    assert lock_path.exists(), f"fresh lock이 잘못 삭제됨: {lock_path}"

    # evidence 파일이 없어야 함
    evidence_path = tmp_path / "memory" / "events" / f"{task_id}.lock-cleanup.json"
    assert not evidence_path.exists(), f"fresh lock에 대한 evidence가 잘못 생성됨: {evidence_path}"


# ---------------------------------------------------------------------------
# 복합: stale + fresh 동시 처리
# ---------------------------------------------------------------------------

def test_cleanup_mixed_locks(tmp_path: Path):
    """stale lock은 삭제, fresh lock은 보존 (동시 처리)."""
    locks_dir = tmp_path / ".tasks" / "locks"

    stale_task = "task-stale-mix"
    fresh_task = "task-fresh-mix"

    # stale: 45분 전
    stale_ts = (datetime.now(timezone.utc) - timedelta(minutes=45)).strftime("%Y-%m-%dT%H:%M:%SZ")
    stale_lock = _make_lock(locks_dir, stale_task, stale_ts)

    # fresh: 10분 전
    fresh_ts = (datetime.now(timezone.utc) - timedelta(minutes=10)).strftime("%Y-%m-%dT%H:%M:%SZ")
    fresh_lock = _make_lock(locks_dir, fresh_task, fresh_ts)

    result = _run(["--cleanup-stale"], cwd=tmp_path)
    assert result.returncode == 0

    assert not stale_lock.exists(), "stale lock이 삭제되지 않음"
    assert fresh_lock.exists(), "fresh lock이 잘못 삭제됨"

    stale_evidence = tmp_path / "memory" / "events" / f"{stale_task}.lock-cleanup.json"
    fresh_evidence = tmp_path / "memory" / "events" / f"{fresh_task}.lock-cleanup.json"
    assert stale_evidence.exists(), "stale evidence 없음"
    assert not fresh_evidence.exists(), "fresh evidence가 잘못 생성됨"
