"""
test_file_check_enhanced.py - file_check 강화 및 duplicate_check 단위 테스트

테스트 항목:
1. file_check: task_id가 보고서에 포함 → PASS (기존 동작 유지)
2. file_check: task_id가 보고서에 미포함 → WARN
3. file_check: SCQA 섹션 모두 존재 → PASS
4. file_check: SCQA 섹션 누락 → WARN (FAIL 아님)
5. duplicate_check: 유사 보고서 없음 → PASS
6. duplicate_check: 유사 보고서 있음 (80%+) → WARN
7. duplicate_check: 보고서 없음 → SKIP
"""

import os
import sys
import tempfile
from pathlib import Path

import pytest

# verifiers 모듈 경로 설정
_QC_DIR = Path(__file__).parent.parent
if str(_QC_DIR) not in sys.path:
    sys.path.insert(0, str(_QC_DIR))

from verifiers import duplicate_check, file_check

# ---------------------------------------------------------------------------
# 헬퍼: 임시 보고서 파일 생성
# ---------------------------------------------------------------------------


def _write_report(reports_dir: str, task_id: str, content: str) -> str:
    """reports_dir에 {task_id}.md 파일을 생성하고 경로 반환."""
    path = os.path.join(reports_dir, f"{task_id}.md")
    with open(path, "w", encoding="utf-8") as f:
        f.write(content)
    return path


# ---------------------------------------------------------------------------
# 1. file_check: task_id 포함 확인
# ---------------------------------------------------------------------------


class TestFileCheckTaskIdInReport:
    """보고서 파일 내 task_id 포함 여부 검증"""

    _SCQA_CONTENT = "S: 상황 설명\n" "C: 문제 발생\n" "Q: 해결 방법은?\n" "A: 다음과 같이 해결\n"

    def test_task_id_present_no_warn(self):
        """task_id가 보고서에 포함 → warnings에 task_id 관련 WARN 없음"""
        task_id = "task-792"
        content = f"# {task_id} 완료 보고서\n{self._SCQA_CONTENT}"
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        # task_id가 있으므로 task_id WARN 없어야 함
        details_str = "\n".join(result["details"])
        assert "task_id not found" not in details_str.lower()

    def test_task_id_absent_warn(self):
        """task_id가 보고서에 미포함 → WARN 반환"""
        task_id = "task-792"
        content = "# 다른 태스크 보고서\n" + self._SCQA_CONTENT
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        assert result["status"] == "WARN", f"task_id 미포함 → WARN 기대, got: {result}"
        details_str = "\n".join(result["details"])
        assert "task_id" in details_str.lower() or "task-792" in details_str

    def test_task_id_absent_details_mention_task_id(self):
        """task_id 미포함 시 details에 task_id 관련 메시지 포함"""
        task_id = "task-792"
        content = "# 복사된 보고서입니다\n" + self._SCQA_CONTENT
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        details_str = "\n".join(result["details"])
        assert "task-792" in details_str or "task_id" in details_str.lower()


# ---------------------------------------------------------------------------
# 2. file_check: SCQA 섹션 확인
# ---------------------------------------------------------------------------


class TestFileCheckSCQASections:
    """보고서 SCQA 섹션 존재 검증"""

    def test_all_scqa_sections_present_no_warn(self):
        """SCQA 섹션 모두 존재 → SCQA 관련 WARN 없음"""
        task_id = "task-792"
        content = (
            f"# {task_id}\n"
            "**S**: 현재 시스템 상황\n"
            "**C**: 문제 발생\n"
            "**Q**: 어떻게 해결?\n"
            "**A**: 다음 방법으로 해결\n"
        )
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        details_str = "\n".join(result["details"])
        assert "SCQA" not in details_str or "WARN" not in result["status"] or "scqa missing" not in details_str.lower()

    def test_scqa_sections_missing_warn_not_fail(self):
        """SCQA 섹션 누락 → WARN (FAIL 아님)"""
        task_id = "task-792"
        content = f"# {task_id}\n이것은 SCQA 포맷이 없는 보고서입니다.\n구현 내용만 기술합니다.\n"
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        assert result["status"] == "WARN", f"SCQA 누락 → WARN 기대, got: {result}"
        assert result["status"] != "FAIL", "SCQA 누락은 FAIL이 아니라 WARN이어야 함"

    def test_scqa_missing_details_mention_scqa(self):
        """SCQA 누락 시 details에 SCQA 관련 메시지 포함"""
        task_id = "task-792"
        content = f"# {task_id}\n일반 보고서 내용입니다.\n"
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        details_str = "\n".join(result["details"])
        assert "SCQA" in details_str or "scqa" in details_str.lower()

    def test_scqa_with_full_word_keywords(self):
        """Situation/Complication/Question/Answer 키워드도 SCQA로 인정"""
        task_id = "task-792"
        content = (
            f"# {task_id}\n"
            "## Situation\n현재 상황\n"
            "## Complication\n문제\n"
            "## Question\n질문\n"
            "## Answer\n답변\n"
        )
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        details_str = "\n".join(result["details"])
        # Situation/Complication/Question/Answer 모두 있으면 SCQA WARN 없어야 함
        assert "SCQA" not in details_str or "missing" not in details_str.lower()

    def test_scqa_partial_missing_warn(self):
        """일부 SCQA 섹션만 있으면 WARN"""
        task_id = "task-792"
        content = (
            f"# {task_id}\n"
            "S: 상황\n"
            "C: 문제\n"
            # Q, A 없음
        )
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = file_check.verify(
                task_id=task_id,
                file_paths=[],
                skip_done=True,
                _reports_dir=tmp_dir,
            )
        assert result["status"] == "WARN"


# ---------------------------------------------------------------------------
# 3. duplicate_check: 유사 보고서 없음 → PASS
# ---------------------------------------------------------------------------


class TestDuplicateCheckNoSimilar:
    """유사 보고서가 없을 때 PASS 반환"""

    def test_no_similar_reports_pass(self):
        """완전히 다른 내용의 보고서들 → PASS"""
        task_id = "task-792"
        current_content = (
            f"# {task_id} 완료 보고서\n"
            "S: 새로운 검증 기능 구현 완료\n"
            "C: 보고서 검증이 필요함\n"
            "Q: 어떻게 자동화할까?\n"
            "A: duplicate_check verifier를 추가하여 해결\n"
        )
        other_content_1 = (
            "# task-100 다른 보고서\n"
            "전혀 다른 내용의 보고서입니다. API 설계 관련.\n"
            "데이터베이스 스키마를 변경하였습니다.\n"
        )
        other_content_2 = (
            "# task-200 또 다른 보고서\n"
            "완전히 새로운 주제의 보고서. UI 개선 관련.\n"
            "사용자 경험을 향상시켰습니다.\n"
        )
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, current_content)
            _write_report(tmp_dir, "task-100", other_content_1)
            _write_report(tmp_dir, "task-200", other_content_2)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)
        assert result["status"] == "PASS", f"유사 보고서 없음 → PASS 기대, got: {result}"

    def test_pass_result_has_required_keys(self):
        """PASS 결과에 status, details 키 존재"""
        task_id = "task-792"
        content = f"# {task_id}\n내용\n"
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)
        assert "status" in result
        assert "details" in result
        assert isinstance(result["details"], list)


# ---------------------------------------------------------------------------
# 4. duplicate_check: 유사 보고서 있음 (80%+) → WARN
# ---------------------------------------------------------------------------


class TestDuplicateCheckHighSimilarity:
    """80% 이상 유사한 보고서 존재 시 WARN 반환"""

    def test_high_similarity_warn(self):
        """거의 동일한 보고서 → WARN"""
        task_id = "task-792"
        base_content = (
            "# 완료 보고서\n"
            "S: 현재 시스템 상황 설명\n"
            "C: 문제가 발생하여 해결이 필요함\n"
            "Q: 어떻게 해결할까?\n"
            "A: 다음 방법으로 해결하였음\n"
            "구현 내용: 로직 수정 및 테스트 추가\n"
            "결론: 정상 동작 확인\n"
        )
        # 현재 보고서 (task_id 추가해서 약간만 다르게)
        current_content = f"# {task_id}\n" + base_content
        # 유사 보고서 (내용이 거의 동일)
        similar_content = "# task-old\n" + base_content

        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, current_content)
            _write_report(tmp_dir, "task-old", similar_content)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)
        assert result["status"] == "WARN", f"80%+ 유사 보고서 존재 → WARN 기대, got: {result}"

    def test_high_similarity_details_mention_similar_file(self):
        """WARN 시 details에 유사한 파일명 포함"""
        task_id = "task-792"
        base_content = "X " * 200  # 200단어 반복으로 높은 유사도 보장
        current_content = f"# {task_id}\n" + base_content
        similar_content = "# task-old\n" + base_content

        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, current_content)
            _write_report(tmp_dir, "task-old", similar_content)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)

        if result["status"] == "WARN":
            details_str = "\n".join(result["details"])
            assert "task-old" in details_str, f"유사 파일명이 details에 포함되어야 함: {details_str}"

    def test_similarity_threshold_exactly_80(self):
        """80% 이상이면 WARN, 미만이면 PASS"""
        task_id = "task-792"
        # 완전히 동일한 내용 → 100% 유사 → WARN
        identical_content = "동일한 내용 " * 50
        current_content = f"# {task_id}\n" + identical_content
        other_content = "# task-other\n" + identical_content

        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, current_content)
            _write_report(tmp_dir, "task-other", other_content)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)
        assert result["status"] == "WARN"


# ---------------------------------------------------------------------------
# 5. duplicate_check: 보고서 없음 → SKIP
# ---------------------------------------------------------------------------


class TestDuplicateCheckNoReport:
    """현재 task_id의 보고서가 없으면 SKIP"""

    def test_current_report_missing_skip(self):
        """현재 task_id 보고서 없음 → SKIP"""
        with tempfile.TemporaryDirectory() as tmp_dir:
            # 다른 보고서만 존재
            _write_report(tmp_dir, "task-100", "# task-100\n내용\n")
            result = duplicate_check.verify("task-nonexistent-99999", _reports_dir=tmp_dir)
        assert result["status"] == "SKIP", f"보고서 없음 → SKIP 기대, got: {result}"

    def test_empty_reports_dir_skip(self):
        """reports 디렉토리가 비어있으면 SKIP"""
        with tempfile.TemporaryDirectory() as tmp_dir:
            result = duplicate_check.verify("task-792", _reports_dir=tmp_dir)
        assert result["status"] == "SKIP"

    def test_no_other_reports_pass_not_skip(self):
        """현재 보고서만 있고 비교 대상 없음 → PASS (비교 대상 없으므로 중복 없음)"""
        task_id = "task-792"
        content = f"# {task_id}\n내용\n"
        with tempfile.TemporaryDirectory() as tmp_dir:
            _write_report(tmp_dir, task_id, content)
            result = duplicate_check.verify(task_id, _reports_dir=tmp_dir)
        # 비교 대상이 없으면 PASS 또는 SKIP (구현에 따라)
        assert result["status"] in ("PASS", "SKIP")

    def test_skip_details_mention_reason(self):
        """SKIP 시 details에 이유 포함"""
        with tempfile.TemporaryDirectory() as tmp_dir:
            result = duplicate_check.verify("task-nonexistent-99999", _reports_dir=tmp_dir)
        assert result["status"] == "SKIP"
        assert len(result["details"]) > 0

    def test_reports_dir_not_exist_skip(self):
        """reports 디렉토리 자체가 없으면 SKIP"""
        result = duplicate_check.verify("task-792", _reports_dir="/tmp/nonexistent_dir_vulcan_test")
        assert result["status"] == "SKIP"
