"""
signature_check.py - task 파일의 완료 시그니처 grep/pytest 검증 verifier
task 파일의 ## 완료 시그니처 섹션을 파싱하여 grep/pytest로 자동 검증.
시그니처 섹션 없으면 SKIP (하위 호환).
"""

import os
import re
import subprocess

GREP_RE = re.compile(r'\[grep\]\s*`([^`]+)`\s*@\s*`([^`]+)`')
PYTEST_RE = re.compile(r'\[pytest\]\s*`([^`]+)`')


def _parse_section(content: str, header: str) -> list[str]:
    """## header 이후 다음 ## 헤더 전까지 줄 목록 반환."""
    lines = content.splitlines()
    in_section = False
    result = []
    for line in lines:
        if line.strip() == f"## {header}":
            in_section = True
            continue
        if in_section:
            if line.startswith("## "):
                break
            result.append(line)
    return result


def _detect_level(content: str) -> str:
    """## 레벨 섹션에서 normal/critical/security 키워드 판별."""
    level_lines = _parse_section(content, "레벨")
    for line in level_lines:
        text = line.strip().lower()
        if not text:
            continue
        if "security" in text:
            return "security"
        if "critical" in text:
            return "critical"
        if "normal" in text:
            return "normal"
        # 첫 번째 비어있지 않은 줄만 검사
        break
    return "normal"


def verify(task_id: str, workspace_root: str = "/home/jay/workspace") -> dict:
    """
    task 파일의 ## 완료 시그니처 섹션을 파싱하여 grep/pytest로 검증.

    Returns:
        {"status": "PASS"|"FAIL"|"SKIP", "details": [...]}
        FAIL 시 추가: "failed_signatures": [...]
    """
    task_path = os.path.join(workspace_root, "memory", "tasks", f"{task_id}.md")

    if not os.path.isfile(task_path):
        return {"status": "SKIP", "details": [f"task 파일 없음: {task_path}"]}

    with open(task_path, "r", encoding="utf-8") as f:
        content = f.read()

    sig_lines = _parse_section(content, "완료 시그니처")
    if not sig_lines:
        return {"status": "SKIP", "details": ["시그니처 섹션 없음 (하위 호환)"]}

    level = _detect_level(content)
    run_pytest = level in ("critical", "security")

    details = []
    failed_signatures = []

    for line in sig_lines:
        line_stripped = line.strip()
        if not line_stripped:
            continue

        grep_match = GREP_RE.search(line_stripped)
        if grep_match:
            pattern = grep_match.group(1)
            rel_path = grep_match.group(2)
            abs_path = os.path.join(workspace_root, rel_path)

            sig_label = f"[grep] `{pattern}` @ `{rel_path}`"

            if not os.path.exists(abs_path):
                msg = f"FAIL {sig_label} — 경로 없음: {abs_path}"
                details.append(msg)
                failed_signatures.append(sig_label)
                continue

            try:
                result = subprocess.run(
                    ["grep", "-rn", pattern, abs_path],
                    capture_output=True,
                    text=True,
                    timeout=30,
                )
                if result.returncode == 0:
                    details.append(f"PASS {sig_label}")
                else:
                    details.append(f"FAIL {sig_label} — 패턴 미발견")
                    failed_signatures.append(sig_label)
            except subprocess.TimeoutExpired:
                msg = f"FAIL {sig_label} — timeout"
                details.append(msg)
                failed_signatures.append(sig_label)
            continue

        pytest_match = PYTEST_RE.search(line_stripped)
        if pytest_match:
            test_path_raw = pytest_match.group(1)
            sig_label = f"[pytest] `{test_path_raw}`"

            if not run_pytest:
                details.append(f"SKIP {sig_label} — normal 레벨, pytest 생략")
                continue

            # 테스트경로::테스트명 형태이므로 :: 기준으로 앞부분만 절대경로로 변환
            if "::" in test_path_raw:
                rel_file, _, test_name = test_path_raw.partition("::")
                abs_test_path = os.path.join(workspace_root, rel_file) + "::" + test_name
            else:
                abs_test_path = os.path.join(workspace_root, test_path_raw)

            try:
                result = subprocess.run(
                    ["python3", "-m", "pytest", abs_test_path, "-x"],
                    capture_output=True,
                    text=True,
                    timeout=120,
                )
                if result.returncode == 0:
                    details.append(f"PASS {sig_label}")
                else:
                    details.append(f"FAIL {sig_label} — pytest 실패")
                    failed_signatures.append(sig_label)
            except subprocess.TimeoutExpired:
                msg = f"FAIL {sig_label} — timeout"
                details.append(msg)
                failed_signatures.append(sig_label)
            continue

    if not details:
        return {"status": "SKIP", "details": ["파싱된 시그니처 없음"]}

    if failed_signatures:
        return {
            "status": "FAIL",
            "details": details,
            "failed_signatures": failed_signatures,
        }

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


# 외부 호출 편의를 위한 alias (시그니처 검증 대상)
def signature_check(task_id: str, workspace_root: str = "/home/jay/workspace") -> dict:
    """verify()의 alias — 완료 시그니처 자동 검증에서 심볼 존재 확인 대상."""
    return verify(task_id, workspace_root)
