#!/usr/bin/env bash
# ci_preflight.sh — 멀티 러너 CI 게이트 (task-2148)
# Usage: bash ci_preflight.sh <project_root> [--affected-only <commit_count>]

PROJECT_ROOT="${1:-}"
AFFECTED_ONLY=0
COMMIT_COUNT=0

if [[ -z "$PROJECT_ROOT" ]]; then
  echo "Usage: $0 <project_root> [--affected-only <commit_count>]" >&2
  exit 1
fi

if [[ ! -d "$PROJECT_ROOT" ]]; then
  echo "Error: '$PROJECT_ROOT' is not a directory." >&2
  exit 1
fi

shift
while [[ $# -gt 0 ]]; do
  case "$1" in
    --affected-only)
      AFFECTED_ONLY=1
      COMMIT_COUNT="${2:-1}"
      shift 2
      ;;
    *)
      shift
      ;;
  esac
done

# --- Affected files (for pytest/vitest/jest) ---
get_affected_test_files() {
  local ext_pattern="$1"
  git -C "$PROJECT_ROOT" diff --name-only "HEAD~${COMMIT_COUNT}" 2>/dev/null \
    | grep -E "$ext_pattern" || true
}

# --- Runner executor ---
# Returns: exit code in RUNNER_EXIT, elapsed seconds in RUNNER_TIME
# Captures output to detect "not found" errors from npx --no-install
RUNNER_OUTPUT_FILE=$(mktemp)
trap 'rm -f "$RUNNER_OUTPUT_FILE"' EXIT

run_with_timeout() {
  local cmd_array=("$@")
  local start end elapsed
  start=$(date +%s)

  timeout 120 "${cmd_array[@]}" >"$RUNNER_OUTPUT_FILE" 2>&1
  local rc=$?

  end=$(date +%s)
  elapsed=$(( end - start ))
  RUNNER_TIME="${elapsed}s"

  if [[ $rc -eq 124 ]]; then
    RUNNER_EXIT="TIMEOUT"
  elif [[ $rc -ne 0 ]] && grep -qiE "not found|command not found|could not resolve|Cannot find module|not available|missing packages|canceled due to missing" "$RUNNER_OUTPUT_FILE" 2>/dev/null; then
    RUNNER_EXIT="NOT_FOUND"
  else
    RUNNER_EXIT="$rc"
  fi
}

# --- Individual runners ---
RUNNERS=()
RUNNER_RESULTS=()
HAS_TIMEOUT=0
HAS_FAIL=0

run_pytest() {
  local extra_args=()
  if [[ $AFFECTED_ONLY -eq 1 ]]; then
    local files
    files=$(get_affected_test_files 'test_[^/]+\.py$')
    if [[ -z "$files" ]]; then
      echo "[CI-PREFLIGHT] runner=pytest exit=SKIP time=0s"
      RUNNER_RESULTS+=("SKIP")
      return
    fi
    read -r -a extra_args <<< "$files"
  fi

  run_with_timeout python3 -m pytest "${extra_args[@]+"${extra_args[@]}"}"
  local rc="$RUNNER_EXIT"

  # command not found → SKIP
  if [[ "$rc" == "127" || "$rc" == "NOT_FOUND" ]]; then
    echo "[CI-PREFLIGHT] runner=pytest exit=SKIP time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("SKIP")
  # pytest exit code 5 = no tests collected → SKIP
  elif [[ "$rc" == "5" ]]; then
    echo "[CI-PREFLIGHT] runner=pytest exit=SKIP time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("SKIP")
  elif [[ "$rc" == "TIMEOUT" ]]; then
    echo "[CI-PREFLIGHT] runner=pytest exit=TIMEOUT time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("TIMEOUT")
    HAS_TIMEOUT=1
  elif [[ "$rc" == "0" ]]; then
    echo "[CI-PREFLIGHT] runner=pytest exit=0 time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("PASS")
  else
    echo "[CI-PREFLIGHT] runner=pytest exit=${rc} time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("FAIL")
    HAS_FAIL=1
  fi
}

run_tsc() {
  # tsc --noEmit은 항상 전체 실행 (affected-only 미적용)
  run_with_timeout npx --no-install tsc --noEmit
  local rc="$RUNNER_EXIT"

  if [[ "$rc" == "TIMEOUT" ]]; then
    echo "[CI-PREFLIGHT] runner=tsc exit=TIMEOUT time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("TIMEOUT")
    HAS_TIMEOUT=1
  elif [[ "$rc" == "127" || "$rc" == "NOT_FOUND" ]]; then
    echo "[CI-PREFLIGHT] runner=tsc exit=SKIP time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("SKIP")
  elif [[ "$rc" == "0" ]]; then
    echo "[CI-PREFLIGHT] runner=tsc exit=0 time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("PASS")
  else
    echo "[CI-PREFLIGHT] runner=tsc exit=${rc} time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("FAIL")
    HAS_FAIL=1
  fi
}

run_vitest() {
  local extra_args=()
  if [[ $AFFECTED_ONLY -eq 1 ]]; then
    local files
    files=$(get_affected_test_files '\.(test|spec)\.ts$')
    if [[ -z "$files" ]]; then
      echo "[CI-PREFLIGHT] runner=vitest exit=SKIP time=0s"
      RUNNER_RESULTS+=("SKIP")
      return
    fi
    read -r -a extra_args <<< "$files"
  fi

  run_with_timeout npx --no-install vitest run "${extra_args[@]+"${extra_args[@]}"}"
  local rc="$RUNNER_EXIT"

  if [[ "$rc" == "TIMEOUT" ]]; then
    echo "[CI-PREFLIGHT] runner=vitest exit=TIMEOUT time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("TIMEOUT")
    HAS_TIMEOUT=1
  elif [[ "$rc" == "127" || "$rc" == "NOT_FOUND" ]]; then
    echo "[CI-PREFLIGHT] runner=vitest exit=SKIP time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("SKIP")
  elif [[ "$rc" == "0" ]]; then
    echo "[CI-PREFLIGHT] runner=vitest exit=0 time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("PASS")
  else
    echo "[CI-PREFLIGHT] runner=vitest exit=${rc} time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("FAIL")
    HAS_FAIL=1
  fi
}

run_jest() {
  local extra_args=()
  if [[ $AFFECTED_ONLY -eq 1 ]]; then
    local files
    files=$(get_affected_test_files '\.(test|spec)\.ts$')
    if [[ -z "$files" ]]; then
      echo "[CI-PREFLIGHT] runner=jest exit=SKIP time=0s"
      RUNNER_RESULTS+=("SKIP")
      return
    fi
    read -r -a extra_args <<< "$files"
  fi

  run_with_timeout npx --no-install jest --ci "${extra_args[@]+"${extra_args[@]}"}"
  local rc="$RUNNER_EXIT"

  if [[ "$rc" == "TIMEOUT" ]]; then
    echo "[CI-PREFLIGHT] runner=jest exit=TIMEOUT time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("TIMEOUT")
    HAS_TIMEOUT=1
  elif [[ "$rc" == "127" || "$rc" == "NOT_FOUND" ]]; then
    echo "[CI-PREFLIGHT] runner=jest exit=SKIP time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("SKIP")
  elif [[ "$rc" == "0" ]]; then
    echo "[CI-PREFLIGHT] runner=jest exit=0 time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("PASS")
  else
    echo "[CI-PREFLIGHT] runner=jest exit=${rc} time=${RUNNER_TIME}"
    RUNNER_RESULTS+=("FAIL")
    HAS_FAIL=1
  fi
}

# --- Tech stack detection ---
cd "$PROJECT_ROOT"

if [[ -f "pyproject.toml" || -f "setup.py" || -f "requirements.txt" ]]; then
  RUNNERS+=("pytest")
fi
if [[ -f "tsconfig.json" ]]; then
  RUNNERS+=("tsc")
fi
if compgen -G "vitest.config.*" > /dev/null 2>&1; then
  RUNNERS+=("vitest")
fi
if compgen -G "jest.config.*" > /dev/null 2>&1; then
  RUNNERS+=("jest")
fi

# --- Execute runners ---
if [[ ${#RUNNERS[@]} -eq 0 ]]; then
  echo "[CI-PREFLIGHT] No runners detected"
  echo "[CI-PREFLIGHT] overall=PASS"
  exit 0
fi

for runner in "${RUNNERS[@]}"; do
  case "$runner" in
    pytest) run_pytest ;;
    tsc)    run_tsc    ;;
    vitest) run_vitest ;;
    jest)   run_jest   ;;
  esac
done

# --- Overall result ---
if [[ $HAS_FAIL -eq 1 ]]; then
  echo "[CI-PREFLIGHT] overall=FAIL"
  exit 1
elif [[ $HAS_TIMEOUT -eq 1 ]]; then
  echo "[CI-PREFLIGHT] overall=WARN"
  exit 2
else
  echo "[CI-PREFLIGHT] overall=PASS"
  exit 0
fi
