"""tests/start_guard/test_lock.py
lock 파일 관련 테스트:
- test_lock_json_format: --update-heartbeat 동작 + heartbeat_timestamp 갱신 확인
- test_lock_missing: lock 없을 때 --update-heartbeat exit 1
- test_atomic_write: sequential 연속 write에서 corruption 없음
"""
from __future__ import annotations

import json
import os
import subprocess
from pathlib import Path

import pytest

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 {})},
    )


# ---------------------------------------------------------------------------
# test_lock_json_format: lock 파일 mock 후 --update-heartbeat 동작 검증
# ---------------------------------------------------------------------------

def test_lock_json_format(tmp_path: Path):
    """lock 파일 mock 후 --update-heartbeat 실행 시 heartbeat_timestamp 갱신 확인."""
    task_id = "task-lock-test"
    locks_dir = tmp_path / ".tasks" / "locks"
    locks_dir.mkdir(parents=True, exist_ok=True)
    lock_path = locks_dir / f"{task_id}.lock"

    # 초기 lock 파일 생성
    old_ts = "2026-01-01T00:00:00Z"
    initial_data = {
        "task_id": task_id,
        "bot": "dev4",
        "pid": 12345,
        "heartbeat_timestamp": old_ts,
        "started_at": old_ts,
        "worktree": str(tmp_path),
        "branch": f"task/{task_id}-dev4",
    }
    lock_path.write_text(json.dumps(initial_data, ensure_ascii=False, indent=2), encoding="utf-8")
    assert lock_path.exists()

    # --update-heartbeat 실행
    result = _run(
        ["--task", task_id, "--update-heartbeat"],
        cwd=tmp_path,
    )
    assert result.returncode == 0, (
        f"--update-heartbeat 실패\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )

    # 갱신된 lock 파일 확인
    updated_data = json.loads(lock_path.read_text(encoding="utf-8"))
    assert "heartbeat_timestamp" in updated_data, "heartbeat_timestamp 필드 없음"
    assert updated_data["heartbeat_timestamp"] != old_ts, (
        f"heartbeat_timestamp가 갱신되지 않음: {updated_data['heartbeat_timestamp']}"
    )
    # 기존 필드 유지 확인
    assert updated_data["task_id"] == task_id
    assert updated_data["bot"] == "dev4"
    assert updated_data["pid"] == 12345


# ---------------------------------------------------------------------------
# test_lock_missing: lock 없을 때 --update-heartbeat exit 1
# ---------------------------------------------------------------------------

def test_lock_missing(tmp_path: Path):
    """lock 파일이 없을 때 --update-heartbeat 실행 시 exit 1 확인."""
    task_id = "task-no-lock"
    locks_dir = tmp_path / ".tasks" / "locks"
    # locks_dir 없음 (lock 파일도 없음)
    assert not (locks_dir / f"{task_id}.lock").exists()

    result = _run(
        ["--task", task_id, "--update-heartbeat"],
        cwd=tmp_path,
    )
    assert result.returncode != 0, (
        f"lock 파일 없는데 exit 0 (비정상)\nstdout: {result.stdout}\nstderr: {result.stderr}"
    )
    assert "[GUARD ERROR]" in result.stderr or "update-heartbeat 실패" in result.stderr, (
        f"에러 메시지 없음\nstderr: {result.stderr}"
    )


# ---------------------------------------------------------------------------
# test_atomic_write: sequential write에서 corruption 없음 확인
# ---------------------------------------------------------------------------

def test_atomic_write(tmp_path: Path):
    """sequential 연속 heartbeat 갱신에서 JSON corruption 없음 확인."""
    task_id = "task-atomic"
    locks_dir = tmp_path / ".tasks" / "locks"
    locks_dir.mkdir(parents=True, exist_ok=True)
    lock_path = locks_dir / f"{task_id}.lock"

    # 초기 lock 파일
    init_ts = "2026-01-01T00:00:00Z"
    initial_data = {
        "task_id": task_id,
        "bot": "dev4",
        "pid": os.getpid(),
        "heartbeat_timestamp": init_ts,
        "started_at": init_ts,
        "worktree": str(tmp_path),
        "branch": f"task/{task_id}-dev4",
    }
    lock_path.write_text(json.dumps(initial_data, ensure_ascii=False, indent=2), encoding="utf-8")

    # 연속 5회 갱신 (sequential)
    for i in range(5):
        result = _run(
            ["--task", task_id, "--update-heartbeat"],
            cwd=tmp_path,
        )
        assert result.returncode == 0, f"갱신 {i+1}회차 실패: {result.stderr}"
        # 매번 유효한 JSON인지 확인
        try:
            data = json.loads(lock_path.read_text(encoding="utf-8"))
        except json.JSONDecodeError as e:
            pytest.fail(f"갱신 {i+1}회차 후 JSON corruption: {e}")
        assert "heartbeat_timestamp" in data
        assert data["task_id"] == task_id

    # 최종 상태 확인
    final_data = json.loads(lock_path.read_text(encoding="utf-8"))
    assert final_data["heartbeat_timestamp"] != init_ts, "최종 heartbeat가 초기값과 동일"
    assert final_data["task_id"] == task_id
    assert final_data["bot"] == "dev4"
