"""task-2422 Fix A 회귀 테스트: watchdog alert 전용화

검증 포인트:
- watchdog 실행 후 timer.json mtime/내용 동일
- .escalate, .superseded_by, .backoff 등 마커 파일이 watchdog에 의해 새로 생성되지 않음
- task-timer.py end가 호출되지 않음 (timer.json end_time 무변경)
- task-2414/2417/2420 사고 시나리오: status=running인 task에 .done이 있어도 status=escalated 박제 X
"""

import json
import os
import re
import subprocess
import tempfile
import time
from pathlib import Path

import pytest

WORKSPACE = Path("/home/jay/workspace")
WATCHDOG_SCRIPT = WORKSPACE / "scripts" / "session-watchdog.sh"


def _make_timers_fixture(tmp: Path, *, status="running", retry=0, with_done=False, with_superseded=False):
    """임시 timer.json + heartbeats 디렉토리 + events 디렉토리 생성"""
    # 디렉토리 구조
    memory = tmp / "memory"
    (memory / "heartbeats").mkdir(parents=True)
    (memory / "events").mkdir()
    (memory / "tasks").mkdir()
    (tmp / "logs").mkdir()

    # task-9999.md (taskfile 존재)
    (memory / "tasks" / "task-9999.md").write_text("# Test task")

    # timer.json
    timers = {
        "tasks": {
            "task-9999": {
                "status": status,
                "team_id": "dev1-team",
                "start_time": "2026-05-01T00:00:00",
                "schedule_id": "test-sched",
                "task_file": "memory/tasks/task-9999.md",
                "retry_count": retry,
                "max_retry": 2,
            }
        }
    }
    (memory / "task-timers.json").write_text(json.dumps(timers, indent=2))

    if with_done:
        (memory / "events" / "task-9999.done").touch()
    if with_superseded:
        (memory / "events" / "task-9999.superseded_by").touch()

    return memory


def _run_watchdog(memory_root: Path, monkeypatch_env=None):
    """수정된 WORKSPACE를 가리키도록 wrapper 스크립트 작성 후 실행"""
    workspace_root = memory_root.parent
    tmp_script = workspace_root / "watchdog_test.sh"
    original = WATCHDOG_SCRIPT.read_text()
    patched = original.replace('WORKSPACE="/home/jay/workspace"', f'WORKSPACE="{workspace_root}"', 1)
    # .env.keys 의존도 우회
    (workspace_root / ".env.keys").write_text("ANU_BOT_TOKEN=dummy\nCOKACDIR_KEY_DEV1=dummy\n")
    tmp_script.write_text(patched)
    tmp_script.chmod(0o755)

    env = os.environ.copy()
    env["WATCHDOG_DRY_RUN"] = "1"
    if monkeypatch_env:
        env.update(monkeypatch_env)

    result = subprocess.run(
        ["bash", str(tmp_script)],
        env=env,
        capture_output=True,
        text=True,
        timeout=30,
    )
    return result


@pytest.fixture
def tmp_workspace():
    with tempfile.TemporaryDirectory() as tmp:
        yield Path(tmp)


def test_watchdog_does_not_mutate_timers_json_normal(tmp_workspace):
    """정상 running task: watchdog 실행 후 timer.json 무변경"""
    memory = _make_timers_fixture(tmp_workspace, status="running")
    timer_file = memory / "task-timers.json"
    before_mtime = timer_file.stat().st_mtime
    before_content = timer_file.read_text()

    _run_watchdog(memory)
    time.sleep(0.1)

    after_mtime = timer_file.stat().st_mtime
    after_content = timer_file.read_text()
    assert before_mtime == after_mtime, "timer.json mtime이 변경됨"
    assert before_content == after_content, "timer.json 내용이 변경됨"


def test_watchdog_does_not_mutate_timers_with_done_marker(tmp_workspace):
    """task-2414/2417/2420 사고 시나리오: .done 존재 시 status=escalated 박제 X"""
    memory = _make_timers_fixture(tmp_workspace, status="running", with_done=True)
    timer_file = memory / "task-timers.json"
    before_content = timer_file.read_text()

    _run_watchdog(memory)

    after_data = json.loads(timer_file.read_text())
    assert after_data["tasks"]["task-9999"]["status"] == "running", "status가 escalated로 박제됨 (회귀)"
    assert timer_file.read_text() == before_content, "timer.json 내용이 변경됨"


def test_watchdog_does_not_mutate_timers_with_superseded_marker(tmp_workspace):
    """superseded 마커 존재 시 status=escalated 박제 X"""
    memory = _make_timers_fixture(tmp_workspace, status="running", with_superseded=True)
    timer_file = memory / "task-timers.json"
    before_content = timer_file.read_text()

    _run_watchdog(memory)

    after_data = json.loads(timer_file.read_text())
    assert after_data["tasks"]["task-9999"]["status"] == "running", "status가 escalated로 박제됨 (회귀)"
    assert timer_file.read_text() == before_content


def test_watchdog_does_not_create_backoff_files(tmp_workspace):
    """watchdog 실행 후 .backoff 파일이 새로 생성되지 않음"""
    memory = _make_timers_fixture(tmp_workspace, status="running")
    backoff_files_before = list((memory / "heartbeats").glob("*.backoff"))

    _run_watchdog(memory)

    backoff_files_after = list((memory / "heartbeats").glob("*.backoff"))
    assert backoff_files_before == backoff_files_after, "backoff 파일이 watchdog에 의해 생성됨"


def test_watchdog_does_not_call_task_timer_end(tmp_workspace):
    """타임 무변경 검증: end_time이 watchdog에 의해 작성되지 않음"""
    memory = _make_timers_fixture(tmp_workspace, status="running", with_done=True)
    timer_file = memory / "task-timers.json"

    _run_watchdog(memory)

    after_data = json.loads(timer_file.read_text())
    task = after_data["tasks"]["task-9999"]
    assert "end_time" not in task or not task["end_time"], "end_time이 watchdog에 의해 작성됨 (mutation)"


def test_watchdog_grep_no_jq_status_write():
    """소스 코드 정적 검증: jq .status = "escalated" write 0건"""
    src = WATCHDOG_SCRIPT.read_text()
    matches = re.findall(r'jq[^|]*\.status\s*=\s*"escalated"', src)
    assert len(matches) == 0, f"jq status 박제 패턴 잔존: {matches}"


def test_watchdog_grep_no_backoff_write():
    """소스 코드 정적 검증: BACKOFF_FILE에 echo 작성 0건"""
    src = WATCHDOG_SCRIPT.read_text()
    matches = re.findall(r'echo[^>]*>\s*"?\$\{?BACKOFF_FILE\}?"?', src)
    assert len(matches) == 0, f"BACKOFF_FILE 쓰기 패턴 잔존: {matches}"


def test_watchdog_bash_syntax_valid():
    """bash -n 통과"""
    result = subprocess.run(
        ["bash", "-n", str(WATCHDOG_SCRIPT)],
        capture_output=True,
        text=True,
    )
    assert result.returncode == 0, f"bash -n 실패: {result.stderr}"
