"""
test_runner.py - pytest 자동 재실행 verifier
subprocess로 pytest를 실행하고 결과를 파싱
"""

import os
import re
import subprocess

DEFAULT_TIMEOUT = 60


def _parse_pytest_output(output: str) -> str:
    """pytest stdout에서 통과/실패 요약 줄을 추출."""
    # 예: "5 passed, 2 failed in 1.23s" 또는 "3 passed in 0.45s"
    patterns = [
        r"(\d+ passed.*?in \d+\.?\d*s)",
        r"(\d+ failed.*?in \d+\.?\d*s)",
        r"(no tests ran.*?in \d+\.?\d*s)",
        r"(\d+ error.*?in \d+\.?\d*s)",
    ]
    for line in reversed(output.splitlines()):
        line = line.strip()
        for pattern in patterns:
            match = re.search(pattern, line, re.IGNORECASE)
            if match:
                return match.group(1)
    return ""


def verify(
    test_dir: str = "",
    test_files: list[str] | None = None,
    timeout: int = DEFAULT_TIMEOUT,
) -> dict:
    """
    지정된 디렉토리 또는 파일 목록에서 pytest를 실행합니다.

    Args:
        test_dir: pytest를 실행할 디렉토리 경로
        test_files: pytest에 개별 파일로 전달할 경로 목록 (None이면 미사용)
        timeout: 최대 실행 시간 (초), 초과 시 SKIP

    Returns:
        {"status": "PASS"|"FAIL"|"SKIP", "details": [...]}
    """
    # test_files가 주어진 경우: 개별 파일 모드
    if test_files is not None:
        existing_files = [f for f in test_files if os.path.isfile(f)]
        if not existing_files:
            return {
                "status": "SKIP",
                "details": ["추론된 테스트 파일 중 존재하는 파일 없음"],
            }
        cmd = [
            "python3",
            "-m",
            "pytest",
            *existing_files,
            "-x",
            "-q",
            "--tb=short",
        ]
    elif not test_dir:
        return {"status": "SKIP", "details": ["No test directory specified"]}
    else:
        if not os.path.exists(test_dir):
            return {"status": "FAIL", "details": [f"Test directory not found: {test_dir}"]}

        if not os.path.isdir(test_dir):
            return {"status": "FAIL", "details": [f"Not a directory: {test_dir}"]}

        cmd = [
            "python3",
            "-m",
            "pytest",
            test_dir,
            "-x",
            "-q",
            "--tb=short",
        ]

    details = [f"Running: {' '.join(cmd)}"]

    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=timeout,
        )

        stdout = result.stdout.strip()
        stderr = result.stderr.strip()

        # 요약 줄 추출
        summary = _parse_pytest_output(stdout)
        if summary:
            details.append(f"pytest result: {summary}")

        # 종료코드 확인
        # pytest 종료코드: 0=all passed, 1=some failed, 2=interrupted, 3=internal error
        # 4=command line usage error, 5=no tests collected
        exit_code = result.returncode

        if exit_code == 0:
            details.append(f"Exit code: {exit_code} (all tests passed)")
            return {"status": "PASS", "details": details}

        elif exit_code == 5:
            details.append(f"Exit code: {exit_code} (no tests collected in {test_dir})")
            return {"status": "SKIP", "details": details}

        else:
            details.append(f"Exit code: {exit_code} (tests failed or error)")
            # 실패한 테스트 줄 포함 (최대 10줄)
            if stdout:
                fail_lines = [
                    line
                    for line in stdout.splitlines()
                    if "FAILED" in line or "ERROR" in line or "error" in line.lower()
                ]
                for line in fail_lines[:10]:
                    details.append(f"  {line.strip()}")
            if stderr:
                details.append(f"stderr: {stderr[:300]}")
            return {"status": "FAIL", "details": details}

    except subprocess.TimeoutExpired:
        details.append(f"Timeout after {timeout}s — skipping test run")
        return {"status": "SKIP", "details": details}

    except FileNotFoundError:
        return {
            "status": "FAIL",
            "details": ["python3 not found — cannot run pytest"],
        }

    except Exception as e:
        return {
            "status": "FAIL",
            "details": [f"Unexpected error running pytest: {e}"],
        }


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

    test_dir = sys.argv[1] if len(sys.argv) > 1 else ""
    t = int(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_TIMEOUT

    result = verify(test_dir=test_dir, timeout=t)
    print(json.dumps(result, ensure_ascii=False, indent=2))
