# pyright: reportMissingImports=false
"""
test_git_evidence_worktree_2507.py — task-2507 회귀 테스트

5 false-positive (fix 후 PASS) + 5 true-positive (기존 룰 유지 FAIL/SKIP)

Note: `teams.shared.verifiers.git_evidence` 는 sys.path 동적 추가로 로드된다.
pyright는 이를 정적 분석으로 해결할 수 없으므로 파일 단위 ignore 처리.
"""

import json
import pathlib
import subprocess
import sys

import pytest

# repo root 추가 (verifier import)
ROOT = pathlib.Path(__file__).resolve().parents[2]  # .../task-2507-dev5
sys.path.insert(0, str(ROOT))

# verifiers 패키지 dummy 등록 (conftest.py와 동일 — __init__.py 절대 import 오류 방지)
import types as _types
if "verifiers" not in sys.modules:
    _verifiers_path = ROOT / "teams" / "dev1" / "qc" / "verifiers"
    _dummy_pkg = _types.ModuleType("verifiers")
    _dummy_pkg.__path__ = [str(_verifiers_path)]  # type: ignore[assignment]
    _dummy_pkg.__package__ = "verifiers"
    sys.modules["verifiers"] = _dummy_pkg


# ---------------------------------------------------------------------------
# 공통 fixture
# ---------------------------------------------------------------------------

@pytest.fixture
def tmp_workspace(tmp_path):
    """임시 workspace + task-timers.json + memory/events/ 디렉토리"""
    workspace = tmp_path / "workspace"
    (workspace / "memory" / "tasks").mkdir(parents=True)
    (workspace / "memory" / "events").mkdir(parents=True)
    (workspace / "memory" / "task-timers.json").write_text('{"tasks": {}}')
    return workspace


@pytest.fixture
def tmp_git_repo(tmp_workspace):
    """workspace 내부에 git init"""
    workspace = tmp_workspace
    subprocess.run(
        ["git", "init", "-b", "main"],
        cwd=workspace, check=True, capture_output=True
    )
    subprocess.run(
        ["git", "config", "user.email", "test@test"],
        cwd=workspace, check=True
    )
    subprocess.run(
        ["git", "config", "user.name", "test"],
        cwd=workspace, check=True
    )
    # 초기 commit
    (workspace / "README.md").write_text("init")
    subprocess.run(["git", "add", "."], cwd=workspace, check=True)
    subprocess.run(
        ["git", "commit", "-m", "init"],
        cwd=workspace, check=True, capture_output=True
    )
    return workspace


def _make_commit(
    repo: pathlib.Path,
    msg: str,
    file_name: str = "f.txt",
    content: str = "x",
) -> str:
    (repo / file_name).write_text(content)
    subprocess.run(["git", "add", "."], cwd=repo, check=True)
    subprocess.run(
        ["git", "commit", "-m", msg],
        cwd=repo, check=True, capture_output=True
    )
    sha = subprocess.run(
        ["git", "rev-parse", "HEAD"],
        cwd=repo, capture_output=True, text=True
    ).stdout.strip()
    return sha


# ---------------------------------------------------------------------------
# False-Positive 테스트 (fix 후 PASS 확인 — 기존엔 오탐 FAIL 발생했던 케이스)
# ---------------------------------------------------------------------------

def test_fp1_squash_merge_timers_evidence(tmp_git_repo):
    """task-2503 시나리오: git log 검색 0건이지만 task-timers의 merge_commit 필드로 PASS"""
    workspace = tmp_git_repo
    # task 파일 (non-code 키워드 없음)
    (workspace / "memory" / "tasks" / "task-2503.md").write_text(
        "# task-2503\n\n## 레벨\nLv.3 코드 작업\n"
    )
    # timers에 merge_commit 필드 박제
    timers = {
        "tasks": {
            "task-2503": {
                "merge_commit": "fc49a9fdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
            }
        }
    }
    (workspace / "memory" / "task-timers.json").write_text(json.dumps(timers))
    # task-2503 commit 없음 → git log 0건, 단 mergeCommit evidence로 PASS

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-2503", str(workspace))
    assert result["status"] == "PASS", f"기대 PASS, 실제 {result}"
    assert any(
        "mergeCommit" in d or "PASS COMMIT_EXISTS" in d
        for d in result["details"]
    ), f"mergeCommit evidence 메시지 없음: {result['details']}"


def test_fp2_regex_escape_plus(tmp_git_repo):
    """task-2487+1: '+' 메타문자가 git grep에서 리터럴로 처리되어야 함

    --fixed-strings 플래그 적용으로 task ID의 '+', '.' 등 메타문자가
    literal로 처리되어야 한다.
    """
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-2487+1.md").write_text(
        "# task-2487+1\n\n## 레벨\nLv.2\n"
    )
    # 정확히 [task-2487+1] prefix commit
    _make_commit(workspace, "[task-2487+1] verifier fix")

    from teams.shared.verifiers.git_evidence import verify  # noqa: PLC0415

    # 커밋은 실제로 존재함 (git --fixed-strings 직접 확인)
    raw = subprocess.run(
        ["git", "log", "--oneline", "--all", "--fixed-strings", "--grep", "task-2487+1"],
        cwd=workspace, capture_output=True, text=True
    )
    assert raw.stdout.strip(), "커밋 자체가 존재하지 않음 (fixture 문제)"

    # verify PASS — --fixed-strings 적용으로 '+' literal 매칭
    result = verify("task-2487+1", str(workspace))
    assert result["status"] == "PASS", f"기대 PASS, 실제 {result}"


def test_fp3_worktree_to_main_fallback(tmp_git_repo, monkeypatch):
    """task-2502: worktree_path가 존재하지 않는 경우 workspace_root로 폴백하여 PASS"""
    main_workspace = tmp_git_repo
    (main_workspace / "memory" / "tasks" / "task-2502.md").write_text(
        "# task-2502\n\n## 레벨\nLv.3\n"
    )
    _make_commit(main_workspace, "[task-2502] essence pass")

    # timers에 존재하지 않는 worktree_path 설정 → primary_dir 탐색 실패 → fallback
    timers = {
        "tasks": {
            "task-2502": {
                "worktree_path": "/nonexistent/path/that/does/not/exist"
            }
        }
    }
    (main_workspace / "memory" / "task-timers.json").write_text(
        json.dumps(timers)
    )

    # WORKSPACE_ROOT_FALLBACK을 main workspace로 지정
    monkeypatch.setenv("WORKSPACE_ROOT_FALLBACK", str(main_workspace))
    # 환경변수 PROJECT_PATH / WORKTREE_PATH 미설정 보장
    monkeypatch.delenv("PROJECT_PATH", raising=False)
    monkeypatch.delenv("WORKTREE_PATH", raising=False)

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-2502", str(main_workspace))
    assert result["status"] == "PASS", f"기대 PASS, 실제 {result}"


def test_fp4_fetch_called(tmp_git_repo):
    """_ensure_origin_main_fetched가 호출되어도 fetch 실패 시 silent — PASS 유지"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-2485.md").write_text(
        "# task-2485\n\n## 레벨\nLv.2\n"
    )
    _make_commit(workspace, "[task-2485] fix fetch silent")

    # origin이 없어 fetch는 실패하지만 silent — commit은 보여야 PASS
    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-2485", str(workspace))
    assert result["status"] == "PASS", (
        f"기대 PASS (fetch silent 실패해도), 실제 {result}"
    )


def test_fp5_merge_commit_evidence_only(tmp_git_repo):
    """git log에 task ID 없고 events 파일의 merge_evidence.merge_commit으로 PASS"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-9999.md").write_text(
        "# task-9999\n\n## 레벨\nLv.2\n"
    )
    # events 파일 생성 (essence-pass-escalated-verifier-limitation 형식)
    events_data = {
        "task_id": "task-9999",
        "merge_evidence": {
            "merge_commit": "deadbeef" + "0" * 32,
            "merged_at": "2026-05-08T11:10:13+09:00",
        },
    }
    (
        workspace / "memory" / "events"
        / "task-9999.essence-pass-escalated-verifier-limitation"
    ).write_text(json.dumps(events_data))

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-9999", str(workspace))
    assert result["status"] == "PASS", f"기대 PASS, 실제 {result}"


# ---------------------------------------------------------------------------
# True-Positive 테스트 (룰 유지 — FAIL / SKIP 이어야 정상)
# ---------------------------------------------------------------------------

def test_tp1_no_commit_no_evidence_fails(tmp_git_repo):
    """커밋 0건 + mergeCommit 0건 → FAIL"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-7777.md").write_text(
        "# task-7777\n\n## 레벨\nLv.2\n"
    )
    # commit, evidence, timers 모두 없음

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-7777", str(workspace))
    assert result["status"] == "FAIL", f"기대 FAIL, 실제 {result}"
    assert "COMMIT_EXISTS" in result.get("failed_checks", []), (
        f"failed_checks에 COMMIT_EXISTS 없음: {result}"
    )


def test_tp2_uncommitted_changes_fails(tmp_git_repo):
    """task scope 내 uncommitted 변경 존재 → FAIL (시스템 자동 파일 제외)

    main의 _filter_dirty_to_task_scope 로직: fallback 모드에서는 파일 경로에
    현재 task ID가 포함되어야 task scope 위반으로 인정.
    """
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-7778.md").write_text(
        "# task-7778\n\n## 레벨\nLv.2\n"
    )
    _make_commit(workspace, "[task-7778] real commit")
    # task scope 내 uncommitted 파일 — 경로에 task-7778 포함
    scope_dir = workspace / "memory" / "plans" / "tasks" / "task-7778"
    scope_dir.mkdir(parents=True, exist_ok=True)
    (scope_dir / "draft.md").write_text("uncommitted task-7778 content")
    subprocess.run(["git", "add", "."], cwd=workspace, check=True)

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-7778", str(workspace))
    assert result["status"] == "FAIL", f"기대 FAIL, 실제 {result}"
    assert "NO_UNCOMMITTED" in result.get("failed_checks", []), (
        f"failed_checks에 NO_UNCOMMITTED 없음: {result}"
    )


def test_tp3_empty_commit_fails(tmp_git_repo):
    """빈 커밋 → FAIL"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-7779.md").write_text(
        "# task-7779\n\n## 레벨\nLv.2\n"
    )
    # 빈 커밋
    subprocess.run(
        ["git", "commit", "--allow-empty", "-m", "[task-7779] empty"],
        cwd=workspace, check=True, capture_output=True
    )

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-7779", str(workspace))
    assert result["status"] == "FAIL", f"기대 FAIL, 실제 {result}"
    assert "NON_EMPTY_COMMIT" in result.get("failed_checks", []), (
        f"failed_checks에 NON_EMPTY_COMMIT 없음: {result}"
    )


def test_tp4_system_auto_files_only_passes(tmp_git_repo):
    """시스템 자동 파일만 uncommitted → uncommitted 검사 통과 → PASS"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-7780.md").write_text(
        "# task-7780\n\n## 레벨\nLv.2\n"
    )
    _make_commit(workspace, "[task-7780] real fix")
    # 시스템 자동 파일만 uncommitted (memory/heartbeats/) — 검사에서 제외되어야 함
    (workspace / "memory" / "heartbeats").mkdir(parents=True, exist_ok=True)
    (workspace / "memory" / "heartbeats" / "x.heartbeat").write_text("h")

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-7780", str(workspace))
    assert result["status"] == "PASS", f"기대 PASS, 실제 {result}"


def test_tp5_non_code_task_skips(tmp_git_repo):
    """non-code task (문서만) → SKIP"""
    workspace = tmp_git_repo
    (workspace / "memory" / "tasks" / "task-7781.md").write_text(
        "# task-7781\n\n## 레벨\n코드 수정 없음 (문서만)\n"
    )

    from teams.shared.verifiers.git_evidence import verify
    result = verify("task-7781", str(workspace))
    assert result["status"] == "SKIP", f"기대 SKIP, 실제 {result}"
