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

CONTAINER_NAME=${STAGING_MYSQL_CONTAINER:-peipei-mysql-staging}
VOLUME_NAME=${STAGING_MYSQL_VOLUME:-peipei-mysql-staging-data}
HOST_PORT=${STAGING_MYSQL_PORT:-3307}
DB_NAME=${STAGING_MYSQL_DB:-play-with}
ROOT_PASSWORD=${STAGING_MYSQL_ROOT_PASSWORD:-root}
MYSQL_IMAGE=${STAGING_MYSQL_IMAGE:-mysql:8.0.32}

usage() {
  cat <<USAGE
Usage: $0 <path-to-backup.sql[.gz|.xz]>

Recreates the local staging MySQL container (${CONTAINER_NAME}) and imports the given SQL dump.
Environment overrides: STAGING_MYSQL_CONTAINER, STAGING_MYSQL_VOLUME, STAGING_MYSQL_PORT,
  STAGING_MYSQL_DB, STAGING_MYSQL_ROOT_PASSWORD, STAGING_MYSQL_IMAGE.
USAGE
  exit 1
}

if [[ $# -ne 1 ]]; then
  usage
fi

backup_path=$1
if [[ ! -f "$backup_path" ]]; then
  echo "[ERROR] Backup file not found: $backup_path" >&2
  exit 1
fi

if ! command -v docker >/dev/null 2>&1; then
  echo "[ERROR] docker command not found" >&2
  exit 1
fi

port_in_use() {
  if command -v lsof >/dev/null 2>&1; then
    lsof -iTCP:"$HOST_PORT" -sTCP:LISTEN -Pn >/dev/null 2>&1 && return 0
  fi
  if command -v netstat >/dev/null 2>&1; then
    netstat -an | grep -E "\.$HOST_PORT .*LISTEN" >/dev/null 2>&1 && return 0
  fi
  return 1
}

confirm_remove() {
  local prompt="$1"
  read -r -p "$prompt (yes/no): " reply
  if [[ "$reply" != "yes" ]]; then
    echo "操作已取消"
    exit 1
  fi
}

existing_container_id=$(docker ps -a --filter "name=^${CONTAINER_NAME}$" -q)
if [[ -n "$existing_container_id" ]]; then
  echo "[WARN] Container ${CONTAINER_NAME} already exists."
  confirm_remove "Remove the existing staging container and recreate it?"
  docker rm -f "$CONTAINER_NAME" >/dev/null
fi

echo "[INFO] Removing existing volume (if any): ${VOLUME_NAME}"
if docker volume ls -q --filter "name=^${VOLUME_NAME}$" | grep -Fxq "$VOLUME_NAME"; then
  docker volume rm "$VOLUME_NAME" >/dev/null
fi

if port_in_use; then
  containers_on_port=$(docker ps --filter "publish=${HOST_PORT}" --format '{{.ID}}\t{{.Names}}')
  if [[ -n "$containers_on_port" ]]; then
    echo "[WARN] Host port ${HOST_PORT} is currently used by the following container(s):"
    while IFS=$'\t' read -r cid cname; do
      [[ -z "$cid" ]] && continue
      echo "  - ${cname} (${cid})"
    done <<<"$containers_on_port"
    confirm_remove "Stop and remove these container(s)?"
    while IFS=$'\t' read -r cid cname; do
      [[ -z "$cid" ]] && continue
      docker stop "$cid" >/dev/null
      docker rm "$cid" >/dev/null
    done <<<"$containers_on_port"
  else
    echo "[ERROR] Host port ${HOST_PORT} is already in use. Set STAGING_MYSQL_PORT to an unused port or stop the process using it." >&2
    exit 1
  fi
  if port_in_use; then
    echo "[ERROR] Host port ${HOST_PORT} is still in use after stopping containers. Please free the port manually or change STAGING_MYSQL_PORT." >&2
    exit 1
  fi
fi

echo "[INFO] Starting fresh MySQL container ${CONTAINER_NAME}"
docker run -d \
  --name "$CONTAINER_NAME" \
  -p "${HOST_PORT}:3306" \
  -e MYSQL_ROOT_PASSWORD="$ROOT_PASSWORD" \
  -e MYSQL_DATABASE="$DB_NAME" \
  -v "$VOLUME_NAME:/var/lib/mysql" \
  "$MYSQL_IMAGE" \
  --lower_case_table_names=1 \
  --explicit_defaults_for_timestamp=1 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_unicode_ci >/dev/null

echo -n "[INFO] Waiting for MySQL to accept connections"
for attempt in {1..60}; do
  if docker exec "$CONTAINER_NAME" mysqladmin ping -h127.0.0.1 -uroot -p"$ROOT_PASSWORD" --silent >/dev/null 2>&1; then
    echo " - ready"
    break
  fi
  sleep 2
  echo -n "."
  if [[ $attempt -eq 60 ]]; then
    echo "\n[ERROR] MySQL did not become ready in time" >&2
    exit 1
  fi
done

case "$backup_path" in
  *.gz)
    reader=(gzip -dc -- "$backup_path")
    ;;
  *.xz)
    reader=(xz -dc -- "$backup_path")
    ;;
  *.zip)
    reader=(unzip -p -- "$backup_path")
    ;;
  *)
    reader=(cat -- "$backup_path")
    ;;
esac

echo "[INFO] Importing backup $backup_path into ${DB_NAME}"
"${reader[@]}" | docker exec -i "$CONTAINER_NAME" mysql -uroot -p"$ROOT_PASSWORD" --default-character-set=utf8mb4 "$DB_NAME"

echo "[INFO] Staging database restored. Container ${CONTAINER_NAME} is listening on port ${HOST_PORT}."
