"""
git_evidence.py - git 커밋 증거 검증 verifier
task-2031: 코드 커밋 없이 .done 생성 방지

3가지 검증:
1. COMMIT_EXISTS: task ID가 포함된 커밋 최소 1건
2. NO_UNCOMMITTED: uncommitted 변경 없음
3. NON_EMPTY_COMMIT: 마지막 커밋이 빈 커밋이 아님

non-code task (문서만/리서치만) → SKIP
"""

import os
import re
import subprocess


def _is_non_code_task(task_id: str, workspace_root: str) -> bool:
    """task 파일의 ## 레벨 섹션에서 non-code 키워드 판별."""
    task_path = os.path.join(workspace_root, "memory", "tasks", f"{task_id}.md")
    if not os.path.isfile(task_path):
        return False
    try:
        with open(task_path, "r", encoding="utf-8") as f:
            content = f.read()
        # ## 레벨 섹션 내에서만 검사 (본문 설명 텍스트 오탐 방지)
        m = re.search(r"## 레벨\s*\n(.*?)(?=\n## |\Z)", content, re.DOTALL)
        if not m:
            return False
        section = m.group(1)
        return bool(re.search(r"코드 수정 없음|문서 업데이트만|문서만|리서치만", section))
    except OSError:
        return False


def _run_git(args: list[str], cwd: str) -> subprocess.CompletedProcess:
    """git 명령 실행 헬퍼."""
    return subprocess.run(
        ["git"] + args,
        cwd=cwd,
        capture_output=True,
        text=True,
        timeout=30,
    )


def _find_project_root(workspace_root: str) -> str:
    """git rev-parse로 프로젝트 루트 탐지."""
    try:
        result = _run_git(["rev-parse", "--show-toplevel"], workspace_root)
        if result.returncode == 0:
            return result.stdout.strip()
    except (subprocess.TimeoutExpired, OSError):
        pass
    return workspace_root


def verify(task_id: str, workspace_root: str = "/home/jay/workspace") -> dict:
    """
    git 커밋 증거 검증.

    Returns:
        {"status": "PASS"|"FAIL"|"SKIP", "details": [...]}
    """
    # non-code task → SKIP
    if _is_non_code_task(task_id, workspace_root):
        return {
            "status": "SKIP",
            "details": ["non-code task (문서/리서치) — git 검증 SKIP"],
        }

    proj_dir = _find_project_root(workspace_root)
    details = []
    failed = []

    # 1) COMMIT_EXISTS: task ID 커밋 최소 1건
    try:
        result = _run_git(["log", "--oneline", "--all", f"--grep={task_id}"], proj_dir)
        lines = [l for l in result.stdout.strip().splitlines() if l.strip()]
        commit_count = len(lines)
        if commit_count == 0:
            details.append(f"FAIL COMMIT_EXISTS: {task_id} 커밋 0건")
            failed.append("COMMIT_EXISTS")
        else:
            details.append(f"PASS COMMIT_EXISTS: {task_id} 커밋 {commit_count}건")
    except (subprocess.TimeoutExpired, OSError) as e:
        details.append(f"FAIL COMMIT_EXISTS: git 명령 실패 — {e}")
        failed.append("COMMIT_EXISTS")

    # 2) NO_UNCOMMITTED: uncommitted 변경 없음
    try:
        diff_result = _run_git(["diff", "--quiet"], proj_dir)
        cached_result = _run_git(["diff", "--cached", "--quiet"], proj_dir)
        if diff_result.returncode != 0 or cached_result.returncode != 0:
            details.append("FAIL NO_UNCOMMITTED: uncommitted 변경 존재")
            failed.append("NO_UNCOMMITTED")
        else:
            details.append("PASS NO_UNCOMMITTED: uncommitted 변경 없음")
    except (subprocess.TimeoutExpired, OSError) as e:
        details.append(f"FAIL NO_UNCOMMITTED: git 명령 실패 — {e}")
        failed.append("NO_UNCOMMITTED")

    # 3) NON_EMPTY_COMMIT: 빈 커밋 방어
    try:
        hash_result = _run_git(
            ["log", "--all", f"--grep={task_id}", "--format=%H", "-1"], proj_dir
        )
        last_hash = hash_result.stdout.strip()
        if last_hash:
            diff_files_result = _run_git(
                ["diff", "--name-only", f"{last_hash}^..{last_hash}"], proj_dir
            )
            file_lines = [l for l in diff_files_result.stdout.strip().splitlines() if l.strip()]
            diff_file_count = len(file_lines)
            if diff_file_count == 0:
                details.append("FAIL NON_EMPTY_COMMIT: 빈 커밋(변경 파일 0건)")
                failed.append("NON_EMPTY_COMMIT")
            else:
                details.append(f"PASS NON_EMPTY_COMMIT: 변경 파일 {diff_file_count}건")
        else:
            details.append("SKIP NON_EMPTY_COMMIT: task ID 커밋 없음 (COMMIT_EXISTS에서 처리)")
    except (subprocess.TimeoutExpired, OSError) as e:
        details.append(f"FAIL NON_EMPTY_COMMIT: git 명령 실패 — {e}")
        failed.append("NON_EMPTY_COMMIT")

    if failed:
        return {"status": "FAIL", "details": details, "failed_checks": failed}

    return {"status": "PASS", "details": details}
