"""
test_qc_gate.py - qc_verify.py --gate 플래그 기능 테스트

테스트 항목:
1. test_gate_pass_creates_done_file: --gate + 전체 PASS → .done 파일 생성
2. test_gate_warn_creates_done_file: --gate + WARN → .done 파일 생성
3. test_gate_fail_no_done_file: --gate + FAIL → .done 파일 미생성
4. test_no_gate_flag_no_done_file: --gate 없이 실행 → 기존 동작 유지, .done 미생성
5. test_done_file_content: .done 파일의 JSON 내용이 올바른 형식인지 확인
"""

import importlib.util
import json
import os
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch

# qc_verify.py 경로 설정
_WORKSPACE = Path(os.environ.get("WORKSPACE_ROOT", "/home/jay/workspace"))
_QC_VERIFY_PATH = _WORKSPACE / "teams/dev1/qc/qc_verify.py"
_QC_DIR = str(_QC_VERIFY_PATH.parent)

# qc_verify 모듈 동적 로드
spec = importlib.util.spec_from_file_location("qc_verify", str(_QC_VERIFY_PATH))
assert spec is not None and spec.loader is not None
qc_verify = importlib.util.module_from_spec(spec)

# verifiers 하위 모듈을 mock으로 교체하여 import 오류 방지
_MOCK_VERIFIER_NAMES = [
    "verifiers",
    "verifiers.api_health",
    "verifiers.data_integrity",
    "verifiers.file_check",
    "verifiers.pyright_check",
    "verifiers.schema_contract",
    "verifiers.scope_check",
    "verifiers.style_check",
    "verifiers.tdd_check",
    "verifiers.test_runner",
]
for _name in _MOCK_VERIFIER_NAMES:
    if _name not in sys.modules:
        sys.modules[_name] = MagicMock()

# sys.path에 qc 디렉토리 추가 (qc_verify.py 내부 import를 위해)
if _QC_DIR not in sys.path:
    sys.path.insert(0, _QC_DIR)

spec.loader.exec_module(qc_verify)  # type: ignore[union-attr]


# ---------------------------------------------------------------------------
# 헬퍼: 모든 checks를 지정 status로 만드는 mock 결과
# ---------------------------------------------------------------------------

_ALL_CHECKS = [
    "api_health",
    "file_check",
    "data_integrity",
    "test_runner",
    "tdd_check",
    "schema_contract",
    "pyright_check",
    "style_check",
    "scope_check",
]


def _make_checks(status: str) -> dict:
    """모든 check를 동일한 status로 설정한 dict 반환."""
    return {name: {"status": status, "details": []} for name in _ALL_CHECKS}


def _make_result(overall: str) -> dict:
    """build_result()와 동일한 구조의 result dict 반환."""
    checks = _make_checks(overall)
    return {
        "task_id": "task-test-001",
        "verified_at": "2026-03-09T17:50:00",
        "overall": overall,
        "checks": checks,
        "summary": f"9 {overall}",
    }


# ---------------------------------------------------------------------------
# 1. test_gate_pass_creates_done_file
# ---------------------------------------------------------------------------


class TestGatePassCreatesDoneFile:
    """--gate + 전체 PASS → .done 파일이 생성되어야 한다."""

    def test_gate_pass_creates_done_file(self, tmp_path):
        task_id = "task-test-001"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("PASS")
            qc_verify._handle_gate(result, task_id, "dev1-team")

        assert done_path.exists(), f".done 파일이 생성되어야 함: {done_path}"


# ---------------------------------------------------------------------------
# 2. test_gate_warn_creates_done_file
# ---------------------------------------------------------------------------


class TestGateWarnCreatesDoneFile:
    """--gate + WARN → .done 파일이 생성되어야 한다."""

    def test_gate_warn_creates_done_file(self, tmp_path):
        task_id = "task-test-002"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("WARN")
            qc_verify._handle_gate(result, task_id, "dev1-team")

        assert done_path.exists(), f".done 파일이 생성되어야 함: {done_path}"


# ---------------------------------------------------------------------------
# 3. test_gate_fail_no_done_file
# ---------------------------------------------------------------------------


class TestGateFailNoDoneFile:
    """--gate + FAIL → .done 파일이 생성되지 않아야 한다."""

    def test_gate_fail_no_done_file(self, tmp_path):
        task_id = "task-test-003"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("FAIL")
            qc_verify._handle_gate(result, task_id, "dev1-team")

        assert not done_path.exists(), f".done 파일이 생성되면 안 됨: {done_path}"


# ---------------------------------------------------------------------------
# 4. test_no_gate_flag_no_done_file
# ---------------------------------------------------------------------------


class TestNoGateFlagNoDoneFile:
    """--gate 없이 실행 시 기존 동작 유지 — .done 파일이 생성되지 않아야 한다."""

    def test_no_gate_flag_no_done_file(self, tmp_path):
        task_id = "task-test-004"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        # --gate 미전달 시 main()에서 _handle_gate()를 호출하지 않는지 확인
        # run_check를 mock하여 모든 체크를 SKIP 처리
        with (
            patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}),
            patch("sys.argv", ["qc_verify.py", "--task-id", task_id]),
            patch.object(qc_verify, "run_check", return_value={"status": "SKIP", "details": []}),
            patch("builtins.print"),
        ):
            return_code = qc_verify.main()

        assert not done_path.exists(), f"--gate 플래그 없이 실행했으므로 .done 파일이 생성되면 안 됨: {done_path}"
        # exit code는 SKIP이면 0
        assert return_code == 0


# ---------------------------------------------------------------------------
# 5. test_done_file_content
# ---------------------------------------------------------------------------


class TestDoneFileContent:
    """.done 파일의 JSON 내용이 올바른 형식이어야 한다."""

    def test_done_file_content(self, tmp_path):
        task_id = "task-test-005"
        team = "dev1-team"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("PASS")
            qc_verify._handle_gate(result, task_id, team)

        assert done_path.exists()

        with open(done_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        # 필수 키 존재 확인
        assert data["task_id"] == task_id, "task_id가 일치해야 함"
        assert data["team"] == team, "team이 일치해야 함"
        assert data["qc_result"] == "PASS", "qc_result가 PASS이어야 함"
        assert "timestamp" in data, "timestamp 필드가 있어야 함"
        assert data["status"] == "done", "status가 'done'이어야 함"
        assert data["merge_needed"] is False, "merge_needed가 False이어야 함"
        assert data["merge_branch"] is None, "merge_branch가 None이어야 함"

    def test_done_file_content_warn(self, tmp_path):
        """WARN 결과도 qc_result에 올바르게 기록되어야 한다."""
        task_id = "task-test-006"
        team = "dev1-team"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("WARN")
            qc_verify._handle_gate(result, task_id, team)

        assert done_path.exists()

        with open(done_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        assert data["qc_result"] == "WARN", "qc_result가 WARN이어야 함"
        assert data["status"] == "done"

    def test_done_file_timestamp_format(self, tmp_path):
        """timestamp가 ISO 8601 형식(%Y-%m-%dT%H:%M:%S)이어야 한다."""
        import re

        task_id = "task-test-007"
        done_path = tmp_path / "memory" / "events" / f"{task_id}.done"

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("PASS")
            qc_verify._handle_gate(result, task_id, "dev1-team")

        with open(done_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        iso_pattern = r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$"
        assert re.match(iso_pattern, data["timestamp"]), f"timestamp 형식이 올바르지 않음: {data['timestamp']}"

    def test_done_file_parent_dir_auto_created(self, tmp_path):
        """events 디렉토리가 없어도 자동 생성되어야 한다."""
        task_id = "task-test-008"
        events_dir = tmp_path / "memory" / "events"
        done_path = events_dir / f"{task_id}.done"

        # events 디렉토리가 없는 상태에서 시작
        assert not events_dir.exists()

        with patch.dict(os.environ, {"WORKSPACE_ROOT": str(tmp_path)}):
            result = _make_result("PASS")
            qc_verify._handle_gate(result, task_id, "dev1-team")

        assert events_dir.exists(), "memory/events 디렉토리가 자동 생성되어야 함"
        assert done_path.exists(), ".done 파일이 생성되어야 함"
