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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

REMOTE_HOST="${REMOTE_HOST:-hey-01}"
DEPLOY_DIR="${DEPLOY_DIR:-/root/docker/newapi-hey}"
APP_CONTAINER="${APP_CONTAINER:-new-api-hey}"
APP_PORT="${APP_PORT:-3001}"
PUBLIC_URL="${PUBLIC_URL:-https://lztoken.top}"

NODE_IMAGE="${NODE_IMAGE:-node:22-bullseye}"
GO_IMAGE="${GO_IMAGE:-golang:1.26.1-alpine}"
GOPROXY_VALUE="${GOPROXY_VALUE:-https://goproxy.cn,direct}"
FRONT_BUILD_HEAP_MB="${FRONT_BUILD_HEAP_MB:-8192}"

SYNC_EXCLUDES=(
  ".git"
  ".env"
  "docker-compose.yml"
  "data"
  "logs"
  "redis"
  "backups"
  ".update_tmp"
  "web/node_modules"
)

usage() {
  cat <<'EOF'
Usage:
  scripts/deploy-hey-01.sh

Optional environment variables:
  REMOTE_HOST            SSH host alias, default: hey-01
  DEPLOY_DIR             Remote deploy dir, default: /root/docker/newapi-hey
  APP_CONTAINER          Container name, default: new-api-hey
  APP_PORT               Local bind port on remote host, default: 3001
  PUBLIC_URL             Public URL for final check, default: https://lztoken.top
  NODE_IMAGE             Node image for frontend build, default: node:22-bullseye
  GO_IMAGE               Go image for backend build, default: golang:1.26.1-alpine
  GOPROXY_VALUE          GOPROXY for remote build, default: https://goproxy.cn,direct
  FRONT_BUILD_HEAP_MB    Node heap limit in MB, default: 8192
EOF
}

log() {
  printf '[deploy-hey-01] %s\n' "$*"
}

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || {
    printf 'Missing required command: %s\n' "$1" >&2
    exit 1
  }
}

remote_bash() {
  local script="$1"
  shift
  ssh "$REMOTE_HOST" 'bash -s' -- "$@" <<<"$script"
}

sync_source() {
  log "Syncing source to ${REMOTE_HOST}:${DEPLOY_DIR}"
  local rsync_args=(
    -az
    --delete
  )
  local exclude
  for exclude in "${SYNC_EXCLUDES[@]}"; do
    rsync_args+=(--exclude "$exclude")
  done
  rsync "${rsync_args[@]}" "${ROOT_DIR}/" "${REMOTE_HOST}:${DEPLOY_DIR}/"
}

verify_remote_layout() {
  log "Checking remote layout"
  remote_bash '
set -euo pipefail
deploy_dir="$1"
test -d "$deploy_dir"
test -f "$deploy_dir/.env"
test -f "$deploy_dir/docker-compose.yml"
test -f "$deploy_dir/web/package.json"
test -f "$deploy_dir/web/package-lock.json"
test -f "$deploy_dir/web/src/helpers/render.jsx"
test -d "$deploy_dir/data"
test -d "$deploy_dir/logs"
' "$DEPLOY_DIR"
}

build_frontend() {
  log "Building frontend dist on ${REMOTE_HOST}"
  remote_bash '
set -euo pipefail
deploy_dir="$1"
node_image="$2"
heap_mb="$3"

docker run --rm --network host \
  -v "${deploy_dir}:/src" \
  "${node_image}" \
  sh -lc "
    set -e
    rm -rf /tmp/web
    cp -a /src/web /tmp/web
    cd /tmp/web
    npm ci --legacy-peer-deps
    NODE_OPTIONS=--max-old-space-size=${heap_mb} npm run build
    rm -rf /src/web/dist
    cp -a dist /src/web/dist
  "
' "$DEPLOY_DIR" "$NODE_IMAGE" "$FRONT_BUILD_HEAP_MB"
}

build_backend() {
  log "Building backend binary on ${REMOTE_HOST}"
  remote_bash '
set -euo pipefail
deploy_dir="$1"
go_image="$2"
goproxy_value="$3"

docker run --rm --network host \
  -e "GOPROXY=${goproxy_value}" \
  -v "${deploy_dir}:/src" \
  -w /src \
  "${go_image}" \
  sh -lc "
    set -e
    export PATH=/usr/local/go/bin:\$PATH
    VERSION_VALUE=\$(cat VERSION 2>/dev/null || true)
    go mod download
    go build -ldflags \"-s -w -X github.com/QuantumNous/new-api/common.Version=\${VERSION_VALUE}\" -o new-api
  "
' "$DEPLOY_DIR" "$GO_IMAGE" "$GOPROXY_VALUE"
}

swap_binary() {
  log "Replacing binary in ${APP_CONTAINER}"
  remote_bash '
set -euo pipefail
deploy_dir="$1"
app_container="$2"

backup_dir="${deploy_dir}/backups"
mkdir -p "$backup_dir"
ts="$(date +%Y%m%d%H%M%S)"

docker inspect "$app_container" >/dev/null 2>&1
docker cp "${app_container}:/new-api" "${backup_dir}/new-api.${ts}.bak" || true
docker cp "${deploy_dir}/new-api" "${app_container}:/new-api"
docker restart "$app_container" >/dev/null
' "$DEPLOY_DIR" "$APP_CONTAINER"
}

verify_deploy() {
  log "Checking local health endpoint"
  remote_bash '
set -euo pipefail
app_container="$1"
app_port="$2"
public_url="$3"

local_url="http://127.0.0.1:${app_port}/api/status"
ok=0
for _ in $(seq 1 45); do
  if curl -fsS "$local_url" >/dev/null 2>&1; then
    ok=1
    break
  fi
  sleep 2
done

if [[ "$ok" != "1" ]]; then
  echo "Health check failed: ${local_url}" >&2
  docker logs --tail 120 "$app_container" || true
  exit 1
fi

docker ps --filter "name=${app_container}" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
curl -fsS "$local_url" >/dev/null
curl -I -m 20 "$public_url" | sed -n "1,12p"
' "$APP_CONTAINER" "$APP_PORT" "$PUBLIC_URL"
}

main() {
  if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
    usage
    exit 0
  fi

  require_cmd ssh
  require_cmd rsync

  log "Starting deploy to ${REMOTE_HOST}"
  sync_source
  verify_remote_layout
  build_frontend
  build_backend
  swap_binary
  verify_deploy
  log "Deploy completed successfully"
}

main "$@"
