#!/usr/bin/env bash
# Deploy Ujjain Simhastha Mahakumbh apps to production.
# Domain: https://mahakumbh.gventure.live/
#
# Apache path aliases on the main domain:
#   /           → website (public registration)   :5549
#   /admin      → admin UI                         :5551  (Next basePath /admin)
#   /api        → admin APIs                       :5551  (→ /admin/api)
#   /api/v1     → website registration APIs        :5549  (kept on website)
#
# Usage (on the server):
#   bash website/scripts/deploy.sh
#   bash website/scripts/deploy.sh --skip-install
#   bash website/scripts/deploy.sh --init-db --init-security
#   bash website/scripts/deploy.sh --write-apache
#
# Env overrides:
#   SITE_URL          default https://mahakumbh.gventure.live
#   WEBSITE_PORT      default 5549
#   ADMIN_PORT        default 5551
#   PM2_WEBSITE_NAME  default mahakumbh-website
#   PM2_ADMIN_NAME    default mahakumbh-admin

set -euo pipefail

SITE_URL="${SITE_URL:-https://mahakumbh.gventure.live}"
WEBSITE_PORT="${WEBSITE_PORT:-5549}"
ADMIN_PORT="${ADMIN_PORT:-5551}"
PM2_WEBSITE_NAME="${PM2_WEBSITE_NAME:-mahakumbh-website}"
PM2_ADMIN_NAME="${PM2_ADMIN_NAME:-mahakumbh-admin}"

SKIP_INSTALL=0
INIT_DB=0
INIT_SECURITY=0
WRITE_APACHE=0

log()  { printf '\n==> %s\n' "$*"; }
die()  { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

usage() {
  sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'
  exit 0
}

for arg in "$@"; do
  case "$arg" in
    --skip-install)  SKIP_INSTALL=1 ;;
    --init-db)       INIT_DB=1 ;;
    --init-security) INIT_SECURITY=1 ;;
    --write-apache)  WRITE_APACHE=1 ;;
    -h|--help)       usage ;;
    *)               die "Unknown option: $arg (try --help)" ;;
  esac
done

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WEBSITE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
ROOT_DIR="$(cd "$WEBSITE_DIR/.." && pwd)"
ADMIN_DIR="$ROOT_DIR/admin"
APACHE_SNIPPET="$SCRIPT_DIR/apache-mahakumbh.conf"
ECOSYSTEM_FILE="$SCRIPT_DIR/ecosystem.config.cjs"

[[ -f "$WEBSITE_DIR/package.json" ]] || die "website package.json not found at $WEBSITE_DIR"
[[ -f "$ADMIN_DIR/package.json" ]]   || die "admin package.json not found at $ADMIN_DIR"
have node || die "node is required"
have npm  || die "npm is required"

NODE_MAJOR="$(node -p "process.versions.node.split('.')[0]")"
[[ "$NODE_MAJOR" -ge 20 ]] || die "Node.js 20+ required (found $(node -v))"

require_env_file() {
  local dir="$1"
  local file="$dir/.env.local"
  [[ -f "$file" ]] || die "Missing $file — fill production DB/crypto values before deploy"
}

# Always set production public URL (fixes leftover localhost values).
ensure_site_url() {
  local file="$1"
  if grep -q '^NEXT_PUBLIC_SITE_URL=' "$file" 2>/dev/null; then
    sed -i.bak "s|^NEXT_PUBLIC_SITE_URL=.*|NEXT_PUBLIC_SITE_URL=${SITE_URL}|" "$file"
    rm -f "${file}.bak"
    log "Set NEXT_PUBLIC_SITE_URL=${SITE_URL} in $file"
  else
    printf '\nNEXT_PUBLIC_SITE_URL=%s\n' "$SITE_URL" >> "$file"
    log "Appended NEXT_PUBLIC_SITE_URL=${SITE_URL} to $file"
  fi
}

# Force npm start scripts onto the production ports (prevents stale --port 3002).
pin_start_port() {
  local pkg="$1"
  local port="$2"
  node -e '
    const fs = require("fs");
    const path = process.argv[1];
    const port = process.argv[2];
    const pkg = JSON.parse(fs.readFileSync(path, "utf8"));
    pkg.scripts = pkg.scripts || {};
    pkg.scripts.start = "next start --port " + port;
    fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n");
    console.log("Pinned " + path + " start → next start --port " + port);
  ' "$pkg" "$port"
}

write_ecosystem() {
  log "Writing PM2 ecosystem → $ECOSYSTEM_FILE"
  cat > "$ECOSYSTEM_FILE" <<EOF
module.exports = {
  apps: [
    {
      name: "${PM2_WEBSITE_NAME}",
      cwd: "${WEBSITE_DIR}",
      script: "npm",
      args: "start",
      env: {
        NODE_ENV: "production",
        PORT: "${WEBSITE_PORT}",
      },
    },
    {
      name: "${PM2_ADMIN_NAME}",
      cwd: "${ADMIN_DIR}",
      script: "npm",
      args: "start",
      env: {
        NODE_ENV: "production",
        PORT: "${ADMIN_PORT}",
      },
    },
  ],
};
EOF
}

write_apache_snippet() {
  log "Writing Apache reverse-proxy snippet → $APACHE_SNIPPET"
  cat > "$APACHE_SNIPPET" <<EOF
# Mahakumbh — Apache aliases for ${SITE_URL}
# Enable: a2enmod proxy proxy_http headers rewrite
# Include this from the HTTPS vhost, or copy the Proxy* lines into it.
#
# Path map:
#   /admin   → admin UI   (127.0.0.1:${ADMIN_PORT}/admin)
#   /api     → admin API  (127.0.0.1:${ADMIN_PORT}/admin/api)  [admin only]
#   /api/v1  → website registration API (127.0.0.1:${WEBSITE_PORT}/api/v1)
#   /        → public website (127.0.0.1:${WEBSITE_PORT}/)

ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"

# Website registration APIs (must be before the broader /api rule)
ProxyPass        /api/v1  http://127.0.0.1:${WEBSITE_PORT}/api/v1
ProxyPassReverse /api/v1  http://127.0.0.1:${WEBSITE_PORT}/api/v1

# Admin APIs at domain /api → Next admin basePath /admin/api
ProxyPass        /api  http://127.0.0.1:${ADMIN_PORT}/admin/api
ProxyPassReverse /api  http://127.0.0.1:${ADMIN_PORT}/admin/api

# Admin UI at /admin
ProxyPass        /admin  http://127.0.0.1:${ADMIN_PORT}/admin
ProxyPassReverse /admin  http://127.0.0.1:${ADMIN_PORT}/admin

# Public website (catch-all — keep last)
ProxyPass        /  http://127.0.0.1:${WEBSITE_PORT}/
ProxyPassReverse /  http://127.0.0.1:${WEBSITE_PORT}/
EOF
}

free_port() {
  local port="$1"
  if have fuser; then
    fuser -k "${port}/tcp" >/dev/null 2>&1 || true
  elif have lsof; then
    local pids
    pids="$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null || true)"
    if [[ -n "${pids}" ]]; then
      # shellcheck disable=SC2086
      kill -9 $pids >/dev/null 2>&1 || true
    fi
  fi
}

install_and_build() {
  local dir="$1"
  local name="$2"

  log "Deploying $name ($dir)"
  cd "$dir"
  require_env_file "$dir"
  ensure_site_url "$dir/.env.local"

  if [[ "$SKIP_INSTALL" -eq 0 ]]; then
    log "Installing dependencies ($name)"
    if [[ -f package-lock.json ]]; then
      npm ci
    else
      npm install
    fi
  else
    log "Skipping npm install ($name)"
  fi

  log "Building $name"
  NODE_ENV=production npm run build
}

start_pm2_apps() {
  if ! have pm2; then
    printf 'WARN: pm2 not found — build finished; start manually:\n'
    printf '  cd %s && NODE_ENV=production npm start\n' "$WEBSITE_DIR"
    printf '  cd %s && NODE_ENV=production npm start\n' "$ADMIN_DIR"
    return 0
  fi

  write_ecosystem

  log "Stopping old PM2 apps (clears stale port 3002 bindings)"
  pm2 delete "$PM2_WEBSITE_NAME" >/dev/null 2>&1 || true
  pm2 delete "$PM2_ADMIN_NAME" >/dev/null 2>&1 || true
  # Common leftover names / old ports from earlier deploys
  pm2 delete mahakumbh-admin >/dev/null 2>&1 || true
  pm2 delete mahakumbh-website >/dev/null 2>&1 || true

  free_port 3002
  free_port "$WEBSITE_PORT"
  free_port "$ADMIN_PORT"

  log "Starting PM2 apps from ecosystem (website :${WEBSITE_PORT}, admin :${ADMIN_PORT})"
  pm2 start "$ECOSYSTEM_FILE"
  pm2 save
  pm2 status
}

# --- pin ports on disk before build/start ---
log "Pinning production ports in package.json"
pin_start_port "$WEBSITE_DIR/package.json" "$WEBSITE_PORT"
pin_start_port "$ADMIN_DIR/package.json" "$ADMIN_PORT"

# --- always deploy website + admin ---
install_and_build "$WEBSITE_DIR" "website"
install_and_build "$ADMIN_DIR" "admin"

if [[ "$INIT_DB" -eq 1 ]]; then
  log "Initializing website database schema"
  (cd "$WEBSITE_DIR" && npm run db:init)
fi

if [[ "$INIT_SECURITY" -eq 1 ]]; then
  log "Initializing security tables (website + admin)"
  (cd "$WEBSITE_DIR" && npm run db:init-security)
  (cd "$ADMIN_DIR" && npm run db:init-security)
fi

start_pm2_apps
write_apache_snippet

if [[ "$WRITE_APACHE" -eq 1 ]]; then
  log "Apache snippet ready at $APACHE_SNIPPET — include it in the HTTPS vhost and reload Apache"
fi

log "Deployment complete"
printf '  Domain:          %s\n' "$SITE_URL"
printf '  Website:         %s/          → 127.0.0.1:%s\n' "$SITE_URL" "$WEBSITE_PORT"
printf '  Admin UI:        %s/admin     → 127.0.0.1:%s/admin\n' "$SITE_URL" "$ADMIN_PORT"
printf '  Admin API:       %s/api       → 127.0.0.1:%s/admin/api\n' "$SITE_URL" "$ADMIN_PORT"
printf '  Registration API:%s/api/v1    → 127.0.0.1:%s/api/v1\n' "$SITE_URL" "$WEBSITE_PORT"
printf '\nVerify admin port:\n'
printf '  pm2 logs %s --lines 20\n' "$PM2_ADMIN_NAME"
printf '  (expect: next start --port %s / localhost:%s)\n' "$ADMIN_PORT" "$ADMIN_PORT"
printf '\nApache proxy snippet: %s\n' "$APACHE_SNIPPET"
printf 'Enable modules: sudo a2enmod proxy proxy_http headers && sudo systemctl reload apache2\n'
