"""
test_cleanup_workspace_protection_2569.py
MT-T4: RC-2 + AD-5 검증
  - cleanup-workspace.py --report 실행 성공 (dry-run 기본)
  - is_protected() task md → True, tmp/old.txt → False
  - _audit_log() 호출 후 cleanup-audit.jsonl에 JSONL 형식 기록
  - protection-list.json valid JSON + 필수 키 존재
"""
import importlib.util
import json
import subprocess
from pathlib import Path

import pytest

WORKSPACE = Path(__file__).resolve().parents[2]
CLEANUP_WS_PY = WORKSPACE / "scripts" / "cleanup-workspace.py"


# ── 헬퍼: cleanup-workspace.py 로드 ───────────────────────────────────────────

def _load_cleanup_workspace():
    """importlib으로 cleanup-workspace.py 동적 로드 (파일명에 하이픈)."""
    spec = importlib.util.spec_from_file_location("cleanup_workspace", CLEANUP_WS_PY)
    assert spec is not None and spec.loader is not None, f"spec 로드 실패: {CLEANUP_WS_PY}"
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


# ── 테스트 1: --report 실행 성공 ──────────────────────────────────────────────

def test_cleanup_workspace_dry_run_default():
    """cleanup-workspace.py --report 실행이 returncode 0으로 성공해야 한다."""
    result = subprocess.run(
        ["python3", str(CLEANUP_WS_PY), "--report"],
        capture_output=True,
        text=True,
        cwd=str(WORKSPACE),
    )
    assert result.returncode == 0, (
        f"cleanup-workspace.py --report 실패 (returncode={result.returncode}).\n"
        f"stdout: {result.stdout[:500]}\n"
        f"stderr: {result.stderr[:500]}"
    )


# ── 테스트 2: is_protected() 보호/비보호 경로 판별 ────────────────────────────

def test_cleanup_workspace_protected_paths_skipped(tmp_path: Path):
    """is_protected()가 task md → True, tmp/old.txt → False를 반환해야 한다."""
    cw = _load_cleanup_workspace()
    setattr(cw, "_PROTECTION_CACHE", None)  # 캐시 클리어

    # 가짜 파일 경로 (실제 파일 생성 불요 — is_protected는 경로 문자열 비교)
    task_md = tmp_path / "memory" / "tasks" / "task-9999.md"
    old_txt = tmp_path / "tmp" / "old.txt"

    # task md는 보호 대상 (protection-list.json의 memory/tasks/ 경로)
    # 단, tmp_path 기준으로 relative_to() 계산 — cleanup_workspace의 is_protected는
    # workspace 인자를 받으므로 tmp_path를 workspace로 전달
    result_task = cw.is_protected(task_md, tmp_path)
    assert result_task is True, (
        f"is_protected({task_md}, {tmp_path})가 False를 반환했습니다. "
        "memory/tasks/ 경로가 보호 대상이어야 합니다."
    )

    # tmp/old.txt는 보호 대상 아님
    result_tmp = cw.is_protected(old_txt, tmp_path)
    assert result_tmp is False, (
        f"is_protected({old_txt}, {tmp_path})가 True를 반환했습니다. "
        "tmp/old.txt는 보호 대상이 아니어야 합니다."
    )


# ── 테스트 3: _audit_log() → cleanup-audit.jsonl JSONL 형식 ───────────────────

def test_audit_log_writes_jsonl_format(tmp_path: Path):
    """_audit_log() 호출 후 cleanup-audit.jsonl에 필수 키가 포함된 JSONL이 기록되어야 한다."""
    cw = _load_cleanup_workspace()

    fake_candidate = "fake/path/to/file.txt"
    fake_action = "skipped_protected"
    fake_reason = "test reason — 회귀 테스트"

    cw._audit_log(tmp_path, fake_candidate, fake_action, fake_reason)

    log_path = tmp_path / "memory" / "logs" / "cleanup-audit.jsonl"
    assert log_path.exists(), f"cleanup-audit.jsonl 파일이 생성되지 않았습니다: {log_path}"

    lines = [line.strip() for line in log_path.read_text(encoding="utf-8").splitlines() if line.strip()]
    assert len(lines) >= 1, "cleanup-audit.jsonl에 기록된 줄이 없습니다."

    # 마지막 줄 파싱
    record = json.loads(lines[-1])
    required_keys = {"ts", "candidate", "action", "reason"}
    missing = required_keys - record.keys()
    assert not missing, (
        f"cleanup-audit.jsonl 레코드에 필수 키 누락: {missing}. "
        f"실제 레코드: {record}"
    )

    # 값 확인
    assert record["candidate"] == fake_candidate
    assert record["action"] == fake_action
    assert record["reason"] == fake_reason


# ── 테스트 4: protection-list.json valid JSON + 필수 키 ───────────────────────

def test_protection_list_json_loads_ok():
    """memory/specs/protection-list.json이 valid JSON으로 파싱되고 필수 키가 모두 존재해야 한다."""
    plist_path = WORKSPACE / "memory" / "specs" / "protection-list.json"
    assert plist_path.exists(), f"protection-list.json 없음: {plist_path}"

    try:
        data = json.loads(plist_path.read_text(encoding="utf-8"))
    except json.JSONDecodeError as e:
        pytest.fail(f"protection-list.json JSON 파싱 실패: {e}")

    required_keys = {"protected_paths", "protected_files", "preserved_lifecycle_paths"}
    missing = required_keys - data.keys()
    assert not missing, (
        f"protection-list.json에 필수 키 누락: {missing}. "
        f"실제 키: {list(data.keys())}"
    )

    # 각 키 타입 확인
    assert isinstance(data["protected_paths"], list), "protected_paths가 list가 아닙니다."
    assert isinstance(data["protected_files"], list), "protected_files가 list가 아닙니다."
    assert isinstance(data["preserved_lifecycle_paths"], list), (
        "preserved_lifecycle_paths가 list가 아닙니다."
    )
    assert len(data["protected_paths"]) > 0, "protected_paths가 비어 있습니다."
