"""
test_file_touch_ratio_check.py - file_touch_ratio_check verifier 테스트

총 4개 케이스:
1. ratio 1.0 → PASS (보고서 파일 = 실제 변경 파일)
2. ratio 0.5 → WARN
3. ratio 0 → FAIL
4. 보고서에 수정 파일 섹션 없음 → SKIP
"""

import sys
import os
from unittest.mock import patch, MagicMock
import subprocess

sys.path.insert(0, "/home/jay/workspace/teams/shared")
from verifiers.file_touch_ratio_check import verify


# --- 공통 헬퍼 -----------------------------------------------------------

def _make_report(tmp_path, task_id: str, file_lines: list[str]) -> None:
    """보고서 파일 생성 헬퍼."""
    reports_dir = tmp_path / "memory" / "reports"
    reports_dir.mkdir(parents=True, exist_ok=True)
    content_lines = ["# 작업 보고서\n", "\n", "## 수정 파일\n", "\n"]
    content_lines.extend(file_lines)
    report_file = reports_dir / f"{task_id}.md"
    report_file.write_text("".join(content_lines), encoding="utf-8")


def _git_rev_parse_ok() -> MagicMock:
    """git rev-parse --git-dir 성공 응답 mock."""
    mock = MagicMock()
    mock.returncode = 0
    mock.stdout = ".git\n"
    mock.stderr = ""
    return mock


def _git_diff_result(files: list[str]) -> MagicMock:
    """git diff --name-only HEAD~5 응답 mock."""
    mock = MagicMock()
    mock.returncode = 0
    mock.stdout = "\n".join(files) + ("\n" if files else "")
    mock.stderr = ""
    return mock


def _make_subprocess_run(diff_files: list[str]):
    """subprocess.run을 git 명령어에 맞게 mock하는 side_effect 함수 반환."""
    def _side_effect(cmd, **kwargs):
        if "rev-parse" in cmd:
            return _git_rev_parse_ok()
        elif "diff" in cmd:
            return _git_diff_result(diff_files)
        raise ValueError(f"Unexpected subprocess.run call: {cmd}")
    return _side_effect


# --- 테스트 케이스 -------------------------------------------------------

def test_ratio_1_0_pass(tmp_path):
    """보고서 파일 2개 모두 실제 변경 → ratio 1.0 → PASS."""
    task_id = "task-test-pass"
    workspace_root = str(tmp_path)

    # 보고서: 테이블 형식
    _make_report(tmp_path, task_id, [
        f"| {workspace_root}/src/foo.py | 수정 |\n",
        f"| {workspace_root}/src/bar.py | 추가 |\n",
    ])

    # git diff: 보고서와 동일한 파일 반환
    diff_files = ["src/foo.py", "src/bar.py"]

    with patch("subprocess.run", side_effect=_make_subprocess_run(diff_files)):
        result = verify(task_id, workspace_root=workspace_root)

    assert result["status"] == "PASS", f"Expected PASS, got {result}"
    assert any("1.00" in d or "ratio" in d.lower() for d in result["details"]), result["details"]


def test_ratio_below_0_5_warn(tmp_path):
    """보고서 파일 3개 중 1개만 실제 변경 → ratio 0.33 (< 0.5) → WARN."""
    task_id = "task-test-warn"
    workspace_root = str(tmp_path)

    # 보고서: 목록 형식 (3개 파일)
    _make_report(tmp_path, task_id, [
        f"- {workspace_root}/src/foo.py\n",
        f"- {workspace_root}/src/bar.py\n",
        f"- {workspace_root}/src/baz.py\n",
    ])

    # git diff: foo.py만 변경됨 → 1/3 ≈ 0.33 < 0.5
    diff_files = ["src/foo.py"]

    with patch("subprocess.run", side_effect=_make_subprocess_run(diff_files)):
        result = verify(task_id, workspace_root=workspace_root)

    assert result["status"] == "WARN", f"Expected WARN, got {result}"
    assert any("0.33" in d for d in result["details"]), result["details"]


def test_ratio_0_fail(tmp_path):
    """보고서 파일 2개 모두 실제 변경 없음 → ratio 0.0 → FAIL."""
    task_id = "task-test-fail"
    workspace_root = str(tmp_path)

    _make_report(tmp_path, task_id, [
        f"| {workspace_root}/src/alpha.py | 수정 |\n",
        f"| {workspace_root}/src/beta.py | 수정 |\n",
    ])

    # git diff: 아무 파일도 변경 안 됨
    diff_files = []

    with patch("subprocess.run", side_effect=_make_subprocess_run(diff_files)):
        result = verify(task_id, workspace_root=workspace_root)

    assert result["status"] == "FAIL", f"Expected FAIL, got {result}"
    assert any("명시된 파일 변경 없음" in d for d in result["details"]), result["details"]


def test_no_modified_files_section_skip(tmp_path):
    """보고서에 수정 파일 섹션 없음 → SKIP."""
    task_id = "task-test-skip"
    workspace_root = str(tmp_path)

    # 수정 파일 경로 없는 보고서
    reports_dir = tmp_path / "memory" / "reports"
    reports_dir.mkdir(parents=True, exist_ok=True)
    report_file = reports_dir / f"{task_id}.md"
    report_file.write_text(
        "# 작업 보고서\n\n## 개요\n\n특별한 내용 없음.\n",
        encoding="utf-8",
    )

    # subprocess.run이 호출되지 않아야 함 (git 확인 전에 SKIP 반환)
    with patch("subprocess.run") as mock_run:
        result = verify(task_id, workspace_root=workspace_root)
        mock_run.assert_not_called()

    assert result["status"] == "SKIP", f"Expected SKIP, got {result}"
    assert any("수정 파일 섹션 없음" in d for d in result["details"]), result["details"]
