#!/usr/bin/env bash

set -euo pipefail

run_with_timeout() {
  local seconds="$1"
  shift

  if command -v timeout >/dev/null 2>&1; then
    timeout "${seconds}" "$@"
    return $?
  fi
  if command -v gtimeout >/dev/null 2>&1; then
    gtimeout "${seconds}" "$@"
    return $?
  fi

  if command -v python3 >/dev/null 2>&1; then
    python3 - "$seconds" "$@" <<'PY'
import subprocess
import sys

timeout_s = int(sys.argv[1])
cmd = sys.argv[2:]
try:
    completed = subprocess.run(cmd, timeout=timeout_s)
    sys.exit(completed.returncode)
except subprocess.TimeoutExpired:
    sys.exit(124)
PY
    return $?
  fi

  "$@"
}

retry_with_backoff() {
  local max_attempts=3
  local attempt=1
  local delay=5

  while [ $attempt -le $max_attempts ]; do
    if "$@"; then
      return 0
    fi

    if [ $attempt -lt $max_attempts ]; then
      echo "⚠ Attempt $attempt failed, retrying in ${delay}s..." >&2
      sleep $delay
      delay=$((delay * 2))
    fi
    attempt=$((attempt + 1))
  done

  return 1
}

retry_with_backoff_timeout() {
  local seconds="$1"
  shift
  local max_attempts=3
  local attempt=1
  local delay=5
  local exit_code=1

  while [ $attempt -le $max_attempts ]; do
    if run_with_timeout "$seconds" "$@"; then
      return 0
    else
      exit_code=$?
    fi
    if [ $attempt -lt $max_attempts ]; then
      echo "⚠ Attempt $attempt failed (exit $exit_code), retrying in ${delay}s..." >&2
      sleep $delay
      delay=$((delay * 2))
    fi
    attempt=$((attempt + 1))
  done

  return $exit_code
}

export -f run_with_timeout
export -f retry_with_backoff
export -f retry_with_backoff_timeout
