"""
회귀 테스트: task-2729+17 GOAL-GATE placeholder hardening
검증 대상: goal_assertion_eval bash 함수 (finish-task.sh 내)
작성자: 벨레스 (개발6팀 테스터)
"""
import os
import re
import shlex
import subprocess
import tempfile
import time

# ── 상수 ────────────────────────────────────────────────────────────────────
WORKTREE = "/home/jay/workspace/.worktrees/task-2729+17-dev6"
SCRIPT = os.environ.get(
    "FINISH_TASK_SCRIPT",
    os.path.join(WORKTREE, "scripts/finish-task.sh"),
)

# subprocess.run 에 공통 적용할 기본 timeout (초)
SUBPROCESS_TIMEOUT = 15


def _call_goal(cmd: str, allowed: str, tmo: int = 30) -> str:
    """goal_assertion_eval 을 라이브러리 모드로 호출하고 stdout 첫 줄 반환."""
    bash_snippet = (
        f"FINISH_TASK_LIB_ONLY=1 source {shlex.quote(SCRIPT)}; "
        f"goal_assertion_eval {shlex.quote(cmd)} {shlex.quote(allowed)} {tmo}"
    )
    result = subprocess.run(
        ["bash", "-c", bash_snippet],
        capture_output=True,
        text=True,
        cwd=WORKTREE,
        timeout=SUBPROCESS_TIMEOUT,
    )
    return result.stdout.strip().splitlines()[0] if result.stdout.strip() else ""


# ── 케이스 1: 미확장 변수($VAR) + 리터럴 ... 동시 포함 → SKIP_PLACEHOLDER ─
def test_case1_mixed_placeholder_var_and_ellipsis():
    """python3 $QC_SCRIPT --gate --task-id ... → SKIP_PLACEHOLDER (실행 전 차단)."""
    cmd = "python3 $QC_SCRIPT --gate --task-id ..."
    allowed = "python3"
    result = _call_goal(cmd, allowed, tmo=5)
    assert result == "SKIP_PLACEHOLDER", (
        f"미확장 변수+리터럴 ... 포함 명령은 SKIP_PLACEHOLDER 이어야 함. got={result!r}"
    )


# ── 케이스 2: 리터럴 ... 만 포함 → SKIP_PLACEHOLDER ────────────────────────
def test_case2_ellipsis_placeholder():
    """cat ... → SKIP_PLACEHOLDER (리터럴 ... 탐지)."""
    cmd = "cat ..."
    allowed = "cat"
    result = _call_goal(cmd, allowed, tmo=5)
    assert result == "SKIP_PLACEHOLDER", (
        f"리터럴 ... 포함 명령은 SKIP_PLACEHOLDER 이어야 함. got={result!r}"
    )


# ── 케이스 3: 미확장 $VAR / ${VAR} → SKIP_PLACEHOLDER ───────────────────────
def test_case3_unexpanded_var_placeholder():
    """python3 ${TASK_ID}.py → SKIP_PLACEHOLDER (미확장 ${VAR} 탐지)."""
    cmd = "python3 ${TASK_ID}.py"
    allowed = "python3"
    result = _call_goal(cmd, allowed, tmo=5)
    assert result == "SKIP_PLACEHOLDER", (
        f"미확장 ${'{TASK_ID}'} 포함 명령은 SKIP_PLACEHOLDER 이어야 함. got={result!r}"
    )


def test_case3b_unexpanded_dollar_var():
    """grep -q $PATTERN /etc/hostname → SKIP_PLACEHOLDER (미확장 $VAR 탐지)."""
    cmd = "grep -q $PATTERN /etc/hostname"
    allowed = "grep"
    result = _call_goal(cmd, allowed, tmo=5)
    assert result == "SKIP_PLACEHOLDER", (
        f"미확장 $VAR 포함 명령은 SKIP_PLACEHOLDER 이어야 함. got={result!r}"
    )


# ── 케이스 4: 정상 assertion 명령 → PASS ────────────────────────────────────
def test_case4_normal_pass():
    """grep -q . /etc/hostname (allowed=grep) → PASS."""
    cmd = "grep -q . /etc/hostname"
    allowed = "grep"
    result = _call_goal(cmd, allowed, tmo=10)
    assert result == "PASS", (
        f"정상 assertion 명령은 PASS 이어야 함. got={result!r}"
    )


# ── 케이스 5: 실패 assertion → FAIL (fail-closed) ───────────────────────────
def test_case5_fail_closed():
    """grep -q ZZZNOTFOUND /etc/hostname (allowed=grep) → FAIL."""
    cmd = "grep -q ZZZNOTFOUND /etc/hostname"
    allowed = "grep"
    result = _call_goal(cmd, allowed, tmo=10)
    assert result == "FAIL", (
        f"비0 exit 명령은 FAIL 이어야 함. got={result!r}"
    )


# ── 케이스 6: timeout 초과 → TIMEOUT (fail-closed) ──────────────────────────
def test_case6_timeout_fail_closed():
    """python3 -c 'import time; time.sleep(10)' (timeout=2) → TIMEOUT."""
    cmd = "python3 -c \"import time; time.sleep(10)\""
    allowed = "python3"
    result = _call_goal(cmd, allowed, tmo=2)
    assert result == "TIMEOUT", (
        f"timeout 초과 명령은 TIMEOUT 이어야 함. got={result!r}"
    )


# ── 케이스 7: placeholder skip 이 hang 안 시킴 ──────────────────────────────
def test_case7_placeholder_does_not_hang():
    """placeholder 명령 호출이 5초 이내 반환 + SKIP_PLACEHOLDER 출력 (전체 hang 방지)."""
    cmd = "python3 ${SLEEP_FOREVER}.py"
    allowed = "python3"
    start = time.monotonic()
    result = _call_goal(cmd, allowed, tmo=30)   # subprocess timeout=15 로 보장
    elapsed = time.monotonic() - start
    assert result == "SKIP_PLACEHOLDER", (
        f"placeholder 명령은 SKIP_PLACEHOLDER 이어야 함. got={result!r}"
    )
    assert elapsed < 5.0, (
        f"placeholder skip 은 5초 이내 반환해야 함. elapsed={elapsed:.2f}s"
    )


# ── 케이스 8: goal_assertions 섹션 없는 task md → 추출 명령 0건 ─────────────
def test_case8_no_goal_assertions_section():
    """## goal_assertions 섹션이 없는 md 에서 추출 명령 0건 (파싱 회귀)."""
    md_content = """# Task 9999

## description
이 태스크는 goal_assertions 섹션이 없습니다.

## checklist
- [ ] 구현 완료
"""
    # finish-task.sh 안의 python 스니펫과 동일한 정규식
    pattern = re.compile(
        r"## goal_assertions.*?\n(.*?)(?=\n##|\Z)",
        re.S,
    )

    with tempfile.TemporaryDirectory() as tmpdir:
        md_path = os.path.join(tmpdir, "task_no_goals.md")
        with open(md_path, "w") as f:
            f.write(md_content)

        with open(md_path) as f:
            content = f.read()

        m = pattern.search(content)
        if m:
            lines = m.group(1).strip().split("\n")
            cmds = []
            for line in lines:
                cmd_match = re.search(r"`([^`]+)`", line)
                if cmd_match:
                    cmds.append(cmd_match.group(1))
        else:
            cmds = []

    assert len(cmds) == 0, (
        f"goal_assertions 섹션 없는 md 에서 추출 명령은 0건이어야 함. got={cmds!r}"
    )


# ── 케이스 9: 금지 키 리터럴 자기 검증 ─────────────────────────────────────
def test_case9_no_raw_key_literals_in_test_file():
    """테스트 파일 소스에 실제 키 리터럴(16진 8자 이상 특정 패턴)이 없음을 자체 검증."""
    test_file_path = os.path.abspath(__file__)
    with open(test_file_path, "r") as f:
        source = f.read()

    # 금지 패턴: 16자 hex 시퀀스가 연속으로 등장하는 경우 (실제 키처럼 보이는 것)
    # 단, test 코드 내부에 검증 목적으로 존재하는 경우는 제외하기 위해
    # 구체적인 알려진 금지 패턴을 검사 (예: 8자+16자 hex 조합)
    # 이 테스트는 하드코딩된 실제 키가 없음을 보장
    forbidden_pattern = re.compile(
        r"\b[0-9a-f]{16}\b",  # 16자 hex = 전형적인 API key fragment 길이
        re.IGNORECASE,
    )
    matches = forbidden_pattern.findall(source)
    # 테스트 소스 자체에는 이런 패턴이 없어야 함
    assert len(matches) == 0, (
        f"테스트 파일에 키 리터럴로 보이는 16자 hex 패턴이 발견됨: {matches!r}"
    )


# ── 케이스 10: ACTIVE=false / 부작용 0 검증 ─────────────────────────────────
def test_case10_no_side_effects_in_tempdir():
    """격리 tempdir 에서 함수 호출 후 신규 파일 0건, .done/.lock 생성 0 검증."""
    with tempfile.TemporaryDirectory() as tmpdir:
        # tempdir 초기 파일 목록
        before = set(os.listdir(tmpdir))

        # 정상 PASS 케이스를 tempdir에서 실행
        bash_snippet = (
            f"FINISH_TASK_LIB_ONLY=1 source {shlex.quote(SCRIPT)}; "
            f"cd {shlex.quote(tmpdir)}; "
            f"goal_assertion_eval 'grep -q . /etc/hostname' 'grep' 5"
        )
        subprocess.run(
            ["bash", "-c", bash_snippet],
            capture_output=True,
            text=True,
            cwd=tmpdir,
            timeout=SUBPROCESS_TIMEOUT,
        )

        after = set(os.listdir(tmpdir))
        new_files = after - before

        assert len(new_files) == 0, (
            f"함수 호출 후 tempdir 에 신규 파일이 생성됨: {new_files!r}"
        )

        # .done / .lock 파일 없음
        for fname in after:
            assert not fname.endswith(".done"), f".done 파일 생성됨: {fname}"
            assert not fname.endswith(".lock"), f".lock 파일 생성됨: {fname}"


def test_case10b_no_systemctl_or_epoch_in_function():
    """goal_assertion_eval 함수 본문에 systemctl enable / activation_epoch 가 없음을 grep 확인."""
    with open(SCRIPT, "r") as f:
        content = f.read()

    # goal_assertion_eval 함수 본문만 추출 (12번째 줄부터 36번째 줄 근방)
    # 함수 전체를 정규식으로 추출
    func_match = re.search(
        r"(goal_assertion_eval\s*\(\)\s*\{.*?\n\})",
        content,
        re.S,
    )
    assert func_match is not None, "goal_assertion_eval 함수를 소스에서 찾지 못함"
    func_body = func_match.group(1)

    assert "systemctl enable" not in func_body, (
        "goal_assertion_eval 함수 본문에 'systemctl enable' 가 존재함 (부작용 위험)"
    )
    assert "activation_epoch" not in func_body, (
        "goal_assertion_eval 함수 본문에 'activation_epoch' 가 존재함 (부작용 위험)"
    )
