"""
file_check.py - 파일 존재/경로 검증 verifier
파일 존재 여부, 크기 > 0 확인
events/{task_id}.done 및 reports/{task_id}.md 확인 포함
보고서 내용 검증: task_id 포함 확인, SCQA 섹션 존재 확인
"""

import os
import re

MEMORY_BASE = "/home/jay/workspace/memory"
EVENTS_DIR = os.path.join(MEMORY_BASE, "events")
REPORTS_DIR = os.path.join(MEMORY_BASE, "reports")


def _check_file(path: str) -> tuple[bool, str]:
    """파일 존재 + 크기 > 0 체크. (ok, detail_message) 반환."""
    try:
        if not os.path.exists(path):
            return False, f"MISSING: {path}"
        if not os.path.isfile(path):
            return False, f"NOT A FILE: {path}"
        size = os.path.getsize(path)
        if size == 0:
            return False, f"EMPTY (0 bytes): {path}"
        return True, f"OK ({size} bytes): {path}"
    except PermissionError:
        return False, f"PERMISSION DENIED: {path}"
    except OSError as e:
        return False, f"OS ERROR: {path} — {e}"


def _find_done_file(task_id: str) -> tuple[bool, str]:
    """
    events/ 디렉토리에서 task_id에 해당하는 .done 파일을 찾습니다.
    실제 파일명 패턴: task-4.4.done, task-4.4.done.clear 등
    """
    if not os.path.isdir(EVENTS_DIR):
        return False, f"events dir not found: {EVENTS_DIR}"

    try:
        entries = os.listdir(EVENTS_DIR)
    except OSError as e:
        return False, f"Cannot read events dir: {e}"

    # task_id로 시작하고 .done을 포함하는 파일 탐색
    matches = [e for e in entries if e.startswith(task_id) and ".done" in e]

    if matches:
        matched_path = os.path.join(EVENTS_DIR, matches[0])
        return True, f"DONE FILE FOUND: {matched_path}"
    else:
        return False, f"NO .done FILE: {EVENTS_DIR}/{task_id}.done (not found)"


def _find_report_file(task_id: str) -> tuple[bool, str]:
    """
    reports/ 디렉토리에서 task_id에 해당하는 .md 파일을 찾습니다.
    패턴: {task_id}.md
    """
    if not os.path.isdir(REPORTS_DIR):
        return False, f"reports dir not found: {REPORTS_DIR}"

    report_path = os.path.join(REPORTS_DIR, f"{task_id}.md")
    if os.path.exists(report_path):
        try:
            size = os.path.getsize(report_path)
            return True, f"REPORT FOUND ({size} bytes): {report_path}"
        except OSError as e:
            return False, f"REPORT READ ERROR: {e}"
    else:
        # 다른 패턴도 탐색 (예: task-4.4.1.md 같은 서브태스크 보고서)
        try:
            entries = os.listdir(REPORTS_DIR)
        except OSError as e:
            return False, f"Cannot read reports dir: {e}"

        matches = [e for e in entries if e.startswith(task_id) and e.endswith(".md")]
        if matches:
            matched_path = os.path.join(REPORTS_DIR, matches[0])
            try:
                size = os.path.getsize(matched_path)
                return True, f"REPORT FOUND ({size} bytes): {matched_path}"
            except OSError:
                return True, f"REPORT FOUND: {matched_path}"
        return False, f"NO REPORT: {REPORTS_DIR}/{task_id}.md (not found)"


def _check_report_content(report_path: str, task_id: str) -> list[str]:
    """
    보고서 내용을 읽어 추가 검증을 수행하고 WARN 메시지 목록을 반환.

    검증 항목:
    1. task_id 문자열 포함 여부 (없으면 WARN)
    2. SCQA 필수 섹션 존재 여부 (없으면 WARN)

    SCQA 패턴:
      S: "**S**:" 또는 "S:" 또는 "Situation"
      C: "**C**:" 또는 "C:" 또는 "Complication"
      Q: "**Q**:" 또는 "Q:" 또는 "Question"
      A: "**A**:" 또는 "A:" 또는 "Answer"
    """
    warns: list[str] = []

    try:
        with open(report_path, encoding="utf-8") as f:
            content = f.read()
    except OSError as e:
        warns.append(f"WARN: 보고서 내용을 읽을 수 없음: {e}")
        return warns

    # 1) task_id 포함 확인
    if task_id and task_id not in content:
        warns.append(f"WARN: task_id '{task_id}'이(가) 보고서에 없음 — 다른 task 보고서를 복사한 가능성")

    # 2) SCQA 필수 섹션 존재 확인
    scqa_patterns: dict[str, list[str]] = {
        "S": [r"\*\*S\*\*:", r"(?<![A-Za-z])S:", r"Situation"],
        "C": [r"\*\*C\*\*:", r"(?<![A-Za-z])C:", r"Complication"],
        "Q": [r"\*\*Q\*\*:", r"(?<![A-Za-z])Q:", r"Question"],
        "A": [r"\*\*A\*\*:", r"(?<![A-Za-z])A:", r"Answer"],
    }

    missing_sections: list[str] = []
    for section, patterns in scqa_patterns.items():
        found = any(re.search(p, content) for p in patterns)
        if not found:
            missing_sections.append(section)

    if missing_sections:
        warns.append(f"WARN: SCQA 섹션 누락 {missing_sections} — SCQA 포맷 권장 (필수 아님)")

    return warns


def verify(task_id: str = "", file_paths: list | None = None, skip_done: bool = False, _reports_dir: str = "") -> dict:
    """
    파일 존재 여부를 검증합니다.

    Args:
        task_id: task ID (events/.done 및 reports/.md 확인에 사용)
        file_paths: 추가로 검사할 파일 경로 목록
        skip_done: True이면 .done 파일 체크를 건너뜀 (--gate 모드에서 사용)
        _reports_dir: (테스트용) reports 디렉토리 경로. 기본값은 REPORTS_DIR.

    Returns:
        {"status": "PASS"|"FAIL"|"WARN"|"SKIP", "details": [...]}
    """
    if file_paths is None:
        file_paths = []

    reports_dir = _reports_dir if _reports_dir else REPORTS_DIR

    details = []
    failures = 0
    total = 0
    content_warns: list[str] = []

    # 1) 사용자 지정 파일 체크
    for path in file_paths:
        ok, msg = _check_file(path)
        details.append(msg)
        total += 1
        if not ok:
            failures += 1

    # 2) .done 파일 체크 (task_id 있을 때, skip_done이 아닐 때)
    if task_id:
        if skip_done:
            details.append(f"SKIPPED .done check (--gate mode will create it)")
        else:
            ok, msg = _find_done_file(task_id)
            details.append(msg)
            total += 1
            if not ok:
                failures += 1

        # 3) 보고서 파일 체크
        # _reports_dir 오버라이드가 있으면 해당 디렉토리에서 직접 확인
        if _reports_dir:
            report_path_exact = os.path.join(reports_dir, f"{task_id}.md")
            if os.path.isfile(report_path_exact):
                try:
                    size = os.path.getsize(report_path_exact)
                    ok, msg = True, f"REPORT FOUND ({size} bytes): {report_path_exact}"
                    found_report_path: str | None = report_path_exact
                except OSError as e:
                    ok, msg = False, f"REPORT READ ERROR: {e}"
                    found_report_path = None
            else:
                ok, msg = False, f"NO REPORT: {reports_dir}/{task_id}.md (not found)"
                found_report_path = None
        else:
            ok, msg = _find_report_file(task_id)
            # 보고서 경로 추출 (내용 검증용)
            if ok:
                # msg에서 경로 추출: "REPORT FOUND (N bytes): /path/to/file"
                parts = msg.split(": ", 1)
                found_report_path = parts[1].strip() if len(parts) > 1 else None
            else:
                found_report_path = None

        details.append(msg)
        total += 1
        if not ok:
            failures += 1
        elif found_report_path and os.path.isfile(found_report_path):
            # 4) 보고서 내용 추가 검증 (task_id 포함, SCQA 섹션)
            content_warns = _check_report_content(found_report_path, task_id)
            details.extend(content_warns)

    if total == 0:
        return {"status": "SKIP", "details": ["No files to check"]}

    passed = total - failures
    details.append(f"{passed}/{total} checks passed")

    if failures > 0:
        status = "FAIL"
    elif content_warns:
        status = "WARN"
    else:
        status = "PASS"

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


if __name__ == "__main__":
    import json
    import sys

    tid = sys.argv[1] if len(sys.argv) > 1 else ""
    paths = sys.argv[2].split(",") if len(sys.argv) > 2 else []

    result = verify(task_id=tid, file_paths=paths)
    print(json.dumps(result, ensure_ascii=False, indent=2))
