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

APP_ROOT="/var/www/front/drop"
STATE_FILE="$APP_ROOT/.deploy-active"
ROUTER_PROCESS="drop-router"
ROUTER_PORT=8300
BLUE_PORT=8301
GREEN_PORT=8302
REVISION="${1:-$(date +%Y%m%d%H%M%S)}"

cd "$APP_ROOT"

if ! command -v node >/dev/null 2>&1; then
  echo "Node.js is not installed on the deployment server." >&2
  exit 1
fi

if ! command -v npm >/dev/null 2>&1; then
  echo "npm is not installed on the deployment server." >&2
  exit 1
fi

if ! command -v pm2 >/dev/null 2>&1; then
  echo "PM2 is not installed. Run: npm install -g pm2" >&2
  exit 1
fi

if [[ -f "$STATE_FILE" ]]; then
  ACTIVE_SLOT="$(tr -d '\r\n' < "$STATE_FILE")"
else
  ACTIVE_SLOT="green"
fi

if [[ "$ACTIVE_SLOT" != "blue" && "$ACTIVE_SLOT" != "green" ]]; then
  echo "Invalid deployment state: $ACTIVE_SLOT" >&2
  exit 1
fi

if [[ "$ACTIVE_SLOT" == "blue" ]]; then
  TARGET_SLOT="green"
  TARGET_PORT="$GREEN_PORT"
else
  TARGET_SLOT="blue"
  TARGET_PORT="$BLUE_PORT"
fi

TARGET_PROCESS="drop-$TARGET_SLOT"

echo "Active slot: $ACTIVE_SLOT"
echo "Deploying slot: $TARGET_SLOT on port $TARGET_PORT"

npm ci --omit=dev

# Replace only the inactive slot. The active process and router keep serving.
pm2 delete "$TARGET_PROCESS" >/dev/null 2>&1 || true
HOST="127.0.0.1" PORT="$TARGET_PORT" NODE_ENV=production DROP_REVISION="$REVISION" \
  pm2 start src/server.js --name "$TARGET_PROCESS" --time --update-env >/dev/null

TARGET_HEALTHY=0
for _ in $(seq 1 60); do
  if curl --fail --silent --show-error "http://127.0.0.1:$TARGET_PORT/healthz" >/dev/null; then
    TARGET_HEALTHY=1
    break
  fi
  sleep 2
done

if [[ "$TARGET_HEALTHY" != "1" ]]; then
  echo "New slot failed its health check. Active slot was not changed." >&2
  pm2 logs "$TARGET_PROCESS" --lines 100 --nostream >&2 || true
  pm2 delete "$TARGET_PROCESS" >/dev/null 2>&1 || true
  exit 1
fi

PREVIOUS_SLOT="$ACTIVE_SLOT"
printf '%s\n' "$TARGET_SLOT" > "$STATE_FILE.next"
mv "$STATE_FILE.next" "$STATE_FILE"

# The stable router starts once and reads .deploy-active for every new request.
# Existing HTTP/WebSocket connections remain attached to their original slot.
if ! pm2 describe "$ROUTER_PROCESS" >/dev/null 2>&1; then
  ROUTER_PORT="$ROUTER_PORT" BLUE_PORT="$BLUE_PORT" GREEN_PORT="$GREEN_PORT" \
    DEPLOY_STATE_FILE="$STATE_FILE" NODE_ENV=production \
    pm2 start src/router.js --name "$ROUTER_PROCESS" --time --update-env >/dev/null
fi

ROUTER_HEALTHY=0
for _ in $(seq 1 30); do
  if curl --fail --silent --show-error "http://127.0.0.1:$ROUTER_PORT/healthz" >/dev/null; then
    ROUTER_HEALTHY=1
    break
  fi
  sleep 2
done

if [[ "$ROUTER_HEALTHY" != "1" ]]; then
  echo "Router verification failed. Rolling back to $PREVIOUS_SLOT." >&2
  printf '%s\n' "$PREVIOUS_SLOT" > "$STATE_FILE.next"
  mv "$STATE_FILE.next" "$STATE_FILE"
  pm2 delete "$TARGET_PROCESS" >/dev/null 2>&1 || true
  exit 1
fi

# Keep the previous slot running as a warm rollback and connection-drain target.
pm2 save >/dev/null
echo "Blue-green switch complete: $ACTIVE_SLOT -> $TARGET_SLOT ($REVISION)"
