#!/usr/bin/env bash
set -euo pipefail

DOWNLOAD_BASE_URL="${DOWNLOAD_BASE_URL:-https://codex.jvniu.com/tg-sales}"
INSTALL_DIR=""
REGISTRY=""
OFFLINE_IMAGE_DIR=""

usage() {
  cat <<'USAGE'
Usage:
  bash upgrade.sh [--install-dir /opt/tg-sales-archive] [--registry registry.example.com/tg-sales] [--offline-image-dir /path/to/images]

This script backs up .env, database and key volumes, refreshes compose/scripts,
loads or pulls new images, runs migrations, rebuilds Laravel config cache, and
runs healthcheck. It never deletes volumes and never overwrites .env.
USAGE
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --install-dir)
      INSTALL_DIR="${2:-}"
      shift 2
      ;;
    --install-dir=*)
      INSTALL_DIR="${1#*=}"
      shift
      ;;
    --registry)
      REGISTRY="${2:-}"
      shift 2
      ;;
    --registry=*)
      REGISTRY="${1#*=}"
      shift
      ;;
    --offline-image-dir)
      OFFLINE_IMAGE_DIR="${2:-}"
      shift 2
      ;;
    --offline-image-dir=*)
      OFFLINE_IMAGE_DIR="${1#*=}"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$INSTALL_DIR" ]]; then
  if [[ -f ./docker-compose.prod.yml ]]; then
    INSTALL_DIR="$(pwd)"
  else
    INSTALL_DIR="/opt/tg-sales-archive"
  fi
fi

cd "$INSTALL_DIR"

if [[ ! -f .env ]]; then
  echo "Missing .env in $INSTALL_DIR. Refusing to upgrade without existing production config." >&2
  exit 1
fi

COMPOSE_FILE="$INSTALL_DIR/docker-compose.prod.yml"
COMPOSE=(docker compose -f "$COMPOSE_FILE")
IMAGE_CACHE_DIR="$INSTALL_DIR/image-cache"
RUNNING_WORKERS=()

if [[ -f "$COMPOSE_FILE" ]]; then
  while IFS= read -r service; do
    RUNNING_WORKERS+=("$service")
  done < <("${COMPOSE[@]}" ps --services --status running 2>/dev/null | grep '^tg-worker-' || true)
fi

download_file() {
  local name="$1"
  local target="$2"
  local tmp
  tmp="$(mktemp)"
  echo "Downloading $name ..."
  curl -fL --progress-bar --retry 3 --retry-delay 2 "$DOWNLOAD_BASE_URL/$name" -o "$tmp"
  mv "$tmp" "$target"
}

set_env() {
  local key="$1"
  local value="$2"
  local tmp
  tmp="$(mktemp)"
  if grep -qE "^${key}=" .env; then
    awk -v key="$key" -v value="$value" '
      BEGIN { done = 0 }
      $0 ~ "^" key "=" { print key "=" value; done = 1; next }
      { print }
      END { if (done == 0) print key "=" value }
    ' .env > "$tmp"
  else
    cp .env "$tmp"
    echo "${key}=${value}" >> "$tmp"
  fi
  mv "$tmp" .env
  chmod 600 .env
}

if [[ -x "$INSTALL_DIR/backup.sh" ]]; then
  "$INSTALL_DIR/backup.sh" --install-dir "$INSTALL_DIR"
else
  tmp_backup="$(mktemp)"
  download_file backup.sh "$tmp_backup"
  chmod +x "$tmp_backup"
  "$tmp_backup" --install-dir "$INSTALL_DIR"
fi

timestamp="$(date +%Y%m%d_%H%M%S)"
if [[ -f "$COMPOSE_FILE" ]]; then
  cp "$COMPOSE_FILE" "$COMPOSE_FILE.bak.$timestamp"
fi

download_file docker-compose.prod.yml "$COMPOSE_FILE"
download_file .env.production.example "$INSTALL_DIR/.env.production.example"
download_file install.sh "$INSTALL_DIR/install.sh"
download_file upgrade.sh "$INSTALL_DIR/upgrade.sh"
download_file backup.sh "$INSTALL_DIR/backup.sh"
download_file healthcheck.sh "$INSTALL_DIR/healthcheck.sh"
chmod +x "$INSTALL_DIR/install.sh" "$INSTALL_DIR/upgrade.sh" "$INSTALL_DIR/backup.sh" "$INSTALL_DIR/healthcheck.sh"

if [[ -n "$REGISTRY" ]]; then
  REGISTRY="${REGISTRY%/}"
  set_env BACKEND_IMAGE "$REGISTRY/backend:phase10"
  set_env WORKER_IMAGE "$REGISTRY/worker:phase10"
  "${COMPOSE[@]}" pull
else
  set_env BACKEND_IMAGE tg-sales-backend:phase10
  set_env WORKER_IMAGE tg-sales-worker:phase10
  source_dir="$OFFLINE_IMAGE_DIR"
  if [[ -z "$source_dir" ]]; then
    mkdir -p "$IMAGE_CACHE_DIR"
    download_file tg-sales-backend-phase10.tar "$IMAGE_CACHE_DIR/tg-sales-backend-phase10.tar"
    download_file tg-sales-worker-phase10.tar "$IMAGE_CACHE_DIR/tg-sales-worker-phase10.tar"
    source_dir="$IMAGE_CACHE_DIR"
  fi
  echo "Loading backend image from $source_dir/tg-sales-backend-phase10.tar ..."
  docker load -i "$source_dir/tg-sales-backend-phase10.tar"
  echo "Loading worker image from $source_dir/tg-sales-worker-phase10.tar ..."
  docker load -i "$source_dir/tg-sales-worker-phase10.tar"
fi

"${COMPOSE[@]}" config >/dev/null
echo "Starting updated services ..."
"${COMPOSE[@]}" up -d mysql redis minio minio-init backend backend-scheduler
echo "Recreating backend services to apply the latest backend image ..."
"${COMPOSE[@]}" up -d --force-recreate backend backend-scheduler
"${COMPOSE[@]}" exec -T backend php artisan migrate --force
"${COMPOSE[@]}" exec -T backend php artisan optimize:clear
"${COMPOSE[@]}" exec -T backend php artisan config:cache
"${COMPOSE[@]}" restart backend backend-scheduler

if [[ "${#RUNNING_WORKERS[@]}" -gt 0 ]]; then
  echo "Recreating previously running workers: ${RUNNING_WORKERS[*]}"
  "${COMPOSE[@]}" up -d --force-recreate "${RUNNING_WORKERS[@]}"
else
  echo "No running workers detected before upgrade. Worker sessions and volumes were preserved."
fi

"$INSTALL_DIR/healthcheck.sh" --install-dir "$INSTALL_DIR"

echo "Upgrade finished. Existing .env and Docker volumes were preserved."
