"""
test_whisper_data_consistency.py

task-2466 surgical fix 회귀 테스트:
- Fix A: bot_status_resolver.py 수정 검증
- Fix B: task-timer.py _write_event_file acked guard 검증
"""

import importlib.util
import json
import sys
from pathlib import Path

# ---------------------------------------------------------------------------
# 워크트리 기준 경로로 명시적으로 모듈 로드 (WORKSPACE_ROOT 우회)
# ---------------------------------------------------------------------------

# 이 테스트 파일은 task-2466-dev1 worktree에서 실행됨
_WORKTREE_ROOT = Path(__file__).parent.parent
_RESOLVER_PATH = _WORKTREE_ROOT / "scripts" / "bot_status_resolver.py"
_TIMER_PATH = _WORKTREE_ROOT / "memory" / "task-timer.py"


def _load_module_from_path(unique_name: str, path: Path):
    """특정 경로의 파일을 unique_name으로 로드 (sys.modules 캐시 독립)"""
    if unique_name in sys.modules:
        del sys.modules[unique_name]
    spec = importlib.util.spec_from_file_location(unique_name, path)
    assert spec is not None, f"모듈 스펙을 찾을 수 없음: {path}"
    module = importlib.util.module_from_spec(spec)
    assert spec.loader is not None
    spec.loader.exec_module(module)
    return module


# 모듈 로드 (unique_name으로 캐시 충돌 방지)
_resolver_mod = _load_module_from_path("bot_status_resolver_2466", _RESOLVER_PATH)
_timer_mod = _load_module_from_path("task_timer_2466", _TIMER_PATH)

classify_status = _resolver_mod.classify_status
TaskTimer = _timer_mod.TaskTimer


# ---------------------------------------------------------------------------
# Fix A-1: _check_markers에 start_guard_fail 키 포함 확인
# ---------------------------------------------------------------------------

def test_check_markers_includes_start_guard_fail(tmp_path, monkeypatch):
    """start-guard-fail.json 파일 만들고 _check_markers 호출 → markers["start_guard_fail"] == True"""
    events_dir = tmp_path / "memory" / "events"
    events_dir.mkdir(parents=True)

    task_id = "task-9999"
    marker_file = events_dir / f"{task_id}.start-guard-fail.json"
    marker_file.write_text("{}")

    monkeypatch.setattr(_resolver_mod, "WORKSPACE_ROOT", str(tmp_path))
    markers = _resolver_mod._check_markers(task_id)

    assert "start_guard_fail" in markers, "_check_markers에 start_guard_fail 키가 없음"
    assert markers["start_guard_fail"] is True, "start-guard-fail.json 존재 시 True여야 함"


def test_check_markers_start_guard_fail_false_when_absent(tmp_path, monkeypatch):
    """start-guard-fail.json 없으면 start_guard_fail == False"""
    events_dir = tmp_path / "memory" / "events"
    events_dir.mkdir(parents=True)

    monkeypatch.setattr(_resolver_mod, "WORKSPACE_ROOT", str(tmp_path))
    markers = _resolver_mod._check_markers("task-0000")

    assert markers["start_guard_fail"] is False


# ---------------------------------------------------------------------------
# Fix A-2: classify_status에 start_guard_fail 분기 확인
# ---------------------------------------------------------------------------

def test_classify_status_start_guard_fail_returns_stale():
    """classify_status(True, 1, None, None, start_guard_fail=True) → STALE"""
    result = classify_status(True, 1, None, None, start_guard_fail=True)
    assert result == "STALE", f"start_guard_fail=True일 때 STALE 기대, 실제: {result}"


def test_classify_status_start_guard_fail_false_normal_alive():
    """start_guard_fail=False이면 기존 로직 동작 (ps_alive + recent commit → ALIVE)"""
    result = classify_status(True, 1, None, None, start_guard_fail=False)
    assert result == "ALIVE"


def test_classify_status_merged_overrides_start_guard_fail():
    """pr_merged_at가 있으면 start_guard_fail 무시 → MERGED"""
    result = classify_status(False, None, "2026-05-01T00:00:00Z", 42, start_guard_fail=True)
    assert result == "MERGED"


# ---------------------------------------------------------------------------
# Fix A-3: resolve()에서 start_guard_fail 전달 확인 (통합)
# ---------------------------------------------------------------------------

def test_resolve_with_start_guard_fail_returns_stalled_verdict(tmp_path, monkeypatch):
    """start-guard-fail.json 존재 + ps 없음 → verdict == stalled"""
    events_dir = tmp_path / "memory" / "events"
    events_dir.mkdir(parents=True)
    timers_dir = tmp_path / "memory"
    timers_dir.mkdir(parents=True, exist_ok=True)

    task_id = "task-2464"
    marker_file = events_dir / f"{task_id}.start-guard-fail.json"
    marker_file.write_text(json.dumps({"retry_count": 2}))

    # task-timers.json 없어도 동작하도록 빈 파일 생성
    (timers_dir / "task-timers.json").write_text(json.dumps({"tasks": {}}))

    monkeypatch.setattr(_resolver_mod, "WORKSPACE_ROOT", str(tmp_path))

    # ps / git / gh 호출을 mock (subprocess 없이 테스트)
    monkeypatch.setattr(_resolver_mod, "_check_ps", lambda *_a: (False, []))
    monkeypatch.setattr(_resolver_mod, "_get_last_commit", lambda *_a: (None, None))
    monkeypatch.setattr(_resolver_mod, "_get_pr_info", lambda *_a: (None, None, None))

    result = _resolver_mod.resolve(task_id, "dev6")

    assert result["verdict"] == "stalled", f"start_guard_fail 존재 시 verdict=stalled 기대, 실제: {result['verdict']}"
    assert result["bot_status"] == "STALE"
    assert result["markers"]["start_guard_fail"] is True


# ---------------------------------------------------------------------------
# Fix A-4: _check_ps()에서 자기 PID 제외 확인
# ---------------------------------------------------------------------------

def test_check_ps_excludes_self(monkeypatch):
    """ps 호출 시 현재 프로세스 PID와 부모 PID가 결과에서 제외되는지 확인"""
    import os as _os

    self_pid = _os.getpid()
    ppid = _os.getppid()

    # pgrep 결과에 자기 PID가 포함된 것처럼 mock
    fake_stdout = f"{self_pid} python3 test_script task-2464\n{ppid} bash -c task-2464\n99999 claude --team dev6 task-2464\n"

    def fake_run(*_a, **_kw):
        return fake_stdout, 0

    monkeypatch.setattr(_resolver_mod, "_run", fake_run)

    ps_alive, pids = _resolver_mod._check_ps("task-2464", "dev6")

    assert self_pid not in pids, f"자기 PID({self_pid})가 결과에 포함됨"
    assert ppid not in pids, f"부모 PID({ppid})가 결과에 포함됨"
    assert 99999 in pids, "유효한 외부 PID(99999)는 포함되어야 함"
    assert ps_alive is True


# ---------------------------------------------------------------------------
# Fix B: _write_event_file acked guard
# ---------------------------------------------------------------------------

def test_write_event_file_skips_when_acked_exists(tmp_path):
    """.done.acked가 있으면 _write_event_file 호출 시 .done 생성 안 됨"""
    timer = TaskTimer(workspace_path=str(tmp_path))
    events_dir = tmp_path / "memory" / "events"
    events_dir.mkdir(parents=True)

    task_id = "task-2421"
    acked_file = events_dir / f"{task_id}.done.acked"
    acked_file.write_text(json.dumps({"end_time": "2026-05-01T15:19:00+00:00"}))

    from datetime import datetime, timezone
    now = datetime.now(timezone.utc)
    task_data = {"team_id": "dev1", "qc_result": "PASS"}

    timer._write_event_file(task_id, task_data, now, 3600.0)

    done_file = events_dir / f"{task_id}.done"
    assert not done_file.exists(), ".done.acked 존재 시 .done이 생성되면 안 됨"


def test_write_event_file_writes_when_no_acked(tmp_path):
    """.done.acked 없으면 정상적으로 .done 생성"""
    timer = TaskTimer(workspace_path=str(tmp_path))
    events_dir = tmp_path / "memory" / "events"
    events_dir.mkdir(parents=True)

    task_id = "task-2499"

    from datetime import datetime, timezone
    now = datetime.now(timezone.utc)
    task_data = {"team_id": "dev1", "qc_result": "PASS"}

    timer._write_event_file(task_id, task_data, now, 1800.0)

    done_file = events_dir / f"{task_id}.done"
    assert done_file.exists(), ".done.acked 없으면 .done이 생성되어야 함"
    data = json.loads(done_file.read_text())
    assert data["task_id"] == task_id
    assert data["qc_result"] == "PASS"
