#!/usr/bin/env sh

# Bail out immediately on Ctrl+C / SIGTERM. Without this trap, an interrupt
# only kills the current pnpm subprocess; the script then captures its 130
# exit, mistakes it for a normal failure, and runs the next pnpm step.
abort() {
  echo
  echo "Pre-push aborted."
  trap - INT TERM
  kill -- -$$ 2>/dev/null
  exit 130
}
trap abort INT TERM

# Windows Git Bash can miss Node/Pnpm in PATH when hooks run.
# Recover from common PATH drift by hydrating from where.exe.
has_node() {
  command -v node >/dev/null 2>&1 || command -v node.exe >/dev/null 2>&1
}

has_pnpm() {
  command -v pnpm >/dev/null 2>&1 || command -v pnpm.exe >/dev/null 2>&1
}

prepend_windows_exe_dir() {
  EXE_NAME="$1"
  WIN_EXE="$(where.exe "$EXE_NAME" 2>/dev/null | tr -d '\r' | head -n 1)"
  if [ -z "$WIN_EXE" ]; then
    return
  fi

  if command -v cygpath >/dev/null 2>&1; then
    EXE_PATH="$(cygpath -u "$WIN_EXE" 2>/dev/null)"
  else
    EXE_PATH="$(printf '%s' "$WIN_EXE" | sed 's#\\#/#g')"
  fi

  if [ -n "$EXE_PATH" ]; then
    PATH="$(dirname "$EXE_PATH"):$PATH"
    export PATH
  fi
}

if [ "${OS:-}" = "Windows_NT" ]; then
  if ! has_node; then
    prepend_windows_exe_dir node
  fi

  if ! command -v pnpm >/dev/null 2>&1; then
    prepend_windows_exe_dir pnpm
  fi
fi

if ! has_node; then
  echo "Pre-push checks require Node.js, but 'node' is not available on PATH."
  echo "Install Node.js or expose node.exe in PATH, then retry git push."
  exit 1
fi

if ! has_pnpm; then
  echo "Pre-push checks require pnpm, but 'pnpm' is not available on PATH."
  echo "Install pnpm (https://pnpm.io/installation) or expose pnpm.exe in PATH, then retry git push."
  exit 1
fi

# Run format check first (capture exit code without breaking script)
set +e
pnpm format:check
FORMAT_EXIT=$?
set -e

# If format check failed, run format to auto-fix
if [ $FORMAT_EXIT -ne 0 ]; then
  echo "Formatting issues detected. Running format to auto-fix..."
  pnpm format
fi

# Run lint check (capture exit code without breaking script)
set +e
pnpm lint
LINT_EXIT=$?
set -e

# If lint check failed, run lint:fix to auto-fix
if [ $LINT_EXIT -ne 0 ]; then
  echo "Linting issues detected. Running lint:fix to auto-fix..."
  pnpm lint:fix
fi

# Run TypeScript compile check (capture exit code without breaking script)
set +e
pnpm compile
COMPILE_EXIT=$?
set -e

# Run Rust compile checks for both the core and Tauri codebases
set +e
pnpm rust:check
RUST_CHECK_EXIT=$?
set -e

# Enforce scoped cmd-* tokens in components/commands/
set +e
pnpm --dir app run lint:commands-tokens
CMD_TOKENS_EXIT=$?
set -e

# Exit with error if any command still fails after fixes
if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CHECK_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
  echo
  echo "============================================================"
  echo "Pre-push checks failed."
  if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ]; then
    echo "Formatting and/or lint auto-fixes have been applied to your"
    echo "working tree. Please re-commit and push again:"
    echo "    git add -A && git commit -m 'chore: apply auto-fixes'"
    echo "    git push"
  fi
  if [ $COMPILE_EXIT -ne 0 ] || [ $RUST_CHECK_EXIT -ne 0 ] || [ $CMD_TOKENS_EXIT -ne 0 ]; then
    echo "Fix the remaining errors above (TypeScript / Rust / cmd-tokens)"
    echo "before re-pushing — these have no auto-fix path."
  fi
  echo "============================================================"
  exit 1
fi