#!/bin/bash
# =============================================================================
# Parens Patrice Next.js — Production Deployment Script
# Target: Ubuntu/Debian Linux server (gventure)
# App dir:   /var/www/html/gventure/mortgage/web
# Usage (on server, from the Next app dir):
#   cd /var/www/html/gventure/mortgage/web
#   chmod +x deploy/deploy.sh && bash deploy/deploy.sh
# Optional: APP_ROOT=/var/www/html/gventure/mortgage/web bash deploy/deploy.sh
# Optional: SVN_USERNAME=myuser SVN_PASSWORD=mypass bash deploy/deploy.sh
# Domain:  https://mortgage.gventure.live  →  127.0.0.1:4350
# =============================================================================

set -euo pipefail

# ─── Configuration ────────────────────────────────────────────────────────────
APP_NAME="mortgage-nextjs"
# Next.js app on the live server (npm ci, next build, pm2)
APP_ROOT="${APP_ROOT:-/var/www/html/gventure/mortgage/web}"
PROJECT_DIR="${APP_ROOT}"
SVN_ROOT=""
DOMAIN="mortgage.gventure.live"

# Node.js runtime (Apache reverse-proxy ${DOMAIN} → 127.0.0.1:${PORT})
NODE_ENV="production"
PORT="${PORT:-4350}"

# Always deploy from .../mortgage/web. SVN metadata may live in web or the parent checkout.
resolve_paths() {
  local root="${APP_ROOT%/}"
  if [[ -f "${root}/package.json" ]]; then
    PROJECT_DIR="${root}"
  elif [[ -f "${root}/web/package.json" ]]; then
    PROJECT_DIR="${root}/web"
  else
    die "package.json not found in ${root} (expected /var/www/html/gventure/mortgage/web)"
  fi
  APP_ROOT="${PROJECT_DIR}"
  if [[ -d "${PROJECT_DIR}/.svn" ]]; then
    SVN_ROOT="${PROJECT_DIR}"
  elif [[ -d "${PROJECT_DIR}/../.svn" ]]; then
    SVN_ROOT="$(cd "${PROJECT_DIR}/.." && pwd)"
  else
    die "Not an SVN working copy: ${PROJECT_DIR} (or its parent)"
  fi
}

# SVN credentials (override via env when needed)
SVN_USERNAME="${SVN_USERNAME:-vikas}"
SVN_PASSWORD="${SVN_PASSWORD:-aklaverma}"

# Process manager: "pm2" | "systemd" | "none"
PROCESS_MANAGER="pm2"
PM2_APP_NAME="${APP_NAME}"
SYSTEMD_SERVICE="${APP_NAME}"

# Health check after restart (set empty to skip)
HEALTH_CHECK_URL="http://127.0.0.1:${PORT}"
HEALTH_CHECK_RETRIES=10
HEALTH_CHECK_INTERVAL=3

# npm ci flags — use --omit=dev only if you pre-build elsewhere (not recommended)
NPM_CI_FLAGS=""

# ─── Colors ───────────────────────────────────────────────────────────────────
if [[ -t 1 ]] && command -v tput &>/dev/null && [[ $(tput colors 2>/dev/null || echo 0) -ge 8 ]]; then
  C_RESET='\033[0m'
  C_BOLD='\033[1m'
  C_INFO='\033[0;36m'     # Cyan
  C_SUCCESS='\033[0;32m'  # Green
  C_WARN='\033[0;33m'     # Yellow
  C_ERROR='\033[0;31m'    # Red
  C_DIM='\033[0;2m'
else
  C_RESET='' C_BOLD='' C_INFO='' C_SUCCESS='' C_WARN='' C_ERROR='' C_DIM=''
fi

# ─── Logging helpers ──────────────────────────────────────────────────────────
log_info()    { echo -e "${C_INFO}[INFO]${C_RESET}  $(date '+%Y-%m-%d %H:%M:%S') — $*"; }
log_success() { echo -e "${C_SUCCESS}[OK]${C_RESET}    $(date '+%Y-%m-%d %H:%M:%S') — $*"; }
log_warn()    { echo -e "${C_WARN}[WARN]${C_RESET}  $(date '+%Y-%m-%d %H:%M:%S') — $*"; }
log_error()   { echo -e "${C_ERROR}[ERROR]${C_RESET} $(date '+%Y-%m-%d %H:%M:%S') — $*" >&2; }

die() {
  log_error "$*"
  exit 1
}

# ─── Deployment timer ─────────────────────────────────────────────────────────
DEPLOY_START=$(date +%s)
DEPLOY_START_HUMAN=$(date '+%Y-%m-%d %H:%M:%S')

print_banner() {
  echo -e "${C_BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}"
  echo -e "${C_BOLD}  Deploying: ${APP_NAME}${C_RESET}"
  echo -e "${C_DIM}  SVN root:  ${SVN_ROOT}${C_RESET}"
  echo -e "${C_DIM}  App dir:   ${PROJECT_DIR}${C_RESET}"
  echo -e "${C_DIM}  Domain:    https://${DOMAIN}${C_RESET}"
  echo -e "${C_DIM}  Port:      ${PORT} (127.0.0.1:${PORT})${C_RESET}"
  echo -e "${C_BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}"
}

print_summary() {
  local end_human end_epoch elapsed mins secs
  end_epoch=$(date +%s)
  end_human=$(date '+%Y-%m-%d %H:%M:%S')
  elapsed=$((end_epoch - DEPLOY_START))
  mins=$((elapsed / 60))
  secs=$((elapsed % 60))

  echo ""
  echo -e "${C_BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}"
  echo -e "${C_SUCCESS}${C_BOLD}  Deployment completed successfully${C_RESET}"
  echo -e "${C_DIM}  Started:  ${DEPLOY_START_HUMAN}${C_RESET}"
  echo -e "${C_DIM}  Finished: ${end_human}${C_RESET}"
  if [[ $mins -gt 0 ]]; then
    echo -e "${C_DIM}  Duration: ${mins}m ${secs}s (${elapsed}s total)${C_RESET}"
  else
    echo -e "${C_DIM}  Duration: ${secs}s${C_RESET}"
  fi
  echo -e "${C_DIM}  Site:     https://${DOMAIN}${C_RESET}"
  echo -e "${C_DIM}  Upstream: http://127.0.0.1:${PORT}${C_RESET}"
  echo -e "${C_BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C_RESET}"
}

# ─── Pre-flight checks ────────────────────────────────────────────────────────
preflight_checks() {
  log_info "Running pre-flight checks..."

  command -v node &>/dev/null || die "Node.js is not installed."
  command -v npm  &>/dev/null || die "npm is not installed."
  command -v svn  &>/dev/null || die "svn is not installed."

  local node_major
  node_major=$(node -p "process.versions.node.split('.')[0]")
  if [[ "${node_major}" -lt 18 ]]; then
    die "Node.js 18+ is required (found: $(node -v))."
  fi

  [[ -d "${PROJECT_DIR}" ]] || die "Server path does not exist: ${PROJECT_DIR}"
  [[ -d "${SVN_ROOT}/.svn" ]] || die "Not an SVN working copy: ${SVN_ROOT}"
  [[ -f "${PROJECT_DIR}/package.json" ]] || die "package.json not found in ${PROJECT_DIR}"

  if [[ "${PROCESS_MANAGER}" == "pm2" ]]; then
    command -v pm2 &>/dev/null || die "PM2 is not installed. Install: npm i -g pm2"
  elif [[ "${PROCESS_MANAGER}" == "systemd" ]]; then
    command -v systemctl &>/dev/null || die "systemctl is not available."
  fi

  log_success "Pre-flight checks passed (Node $(node -v), npm $(npm -v))"
}

# ─── SVN: update latest code ──────────────────────────────────────────────────
pull_latest_code() {
  log_info "Updating code via SVN..."

  cd "${SVN_ROOT}"

  # Strip CRLF if Windows checkout ever reintroduces it
  sed -i 's/\r$//' "${PROJECT_DIR}/deploy/deploy.sh" 2>/dev/null || true

  if [[ -n "${SVN_PASSWORD}" ]]; then
    svn up --username "${SVN_USERNAME}" --password "${SVN_PASSWORD}" --non-interactive
  else
    svn up --username "${SVN_USERNAME}"
  fi

  local svn_rev
  svn_rev=$(svn info --show-item revision 2>/dev/null || echo "unknown")
  log_success "Code updated to SVN revision ${svn_rev}"
}

# ─── Dependencies ─────────────────────────────────────────────────────────────
install_dependencies() {
  log_info "Installing dependencies (npm ci)..."

  cd "${PROJECT_DIR}"

  [[ -f package-lock.json ]] || die "package-lock.json not found. Run 'npm install' locally and commit the lockfile."

  # Clean install for reproducible builds
  npm ci ${NPM_CI_FLAGS}

  log_success "Dependencies installed."
}

# ─── Build ────────────────────────────────────────────────────────────────────
build_application() {
  log_info "Building Next.js application (NODE_ENV=${NODE_ENV})..."

  cd "${PROJECT_DIR}"

  export NODE_ENV="${NODE_ENV}"

  # Remove stale build output to avoid corrupted artifacts
  if [[ -d .next ]]; then
    log_info "Removing previous .next build cache..."
    rm -rf .next
  fi

  npm run build

  # Verify build artifacts exist
  [[ -d .next ]] || die "Build failed: .next directory was not created."
  [[ -f .next/BUILD_ID ]] || die "Build failed: .next/BUILD_ID is missing."

  log_success "Application built successfully (BUILD_ID: $(cat .next/BUILD_ID))."
}

# ─── Restart application ──────────────────────────────────────────────────────
restart_server() {
  log_info "Restarting application via ${PROCESS_MANAGER}..."

  cd "${PROJECT_DIR}"

  case "${PROCESS_MANAGER}" in
    pm2)
      # Prefer ecosystem.config.cjs so PORT/hostname stay fixed for Apache ProxyPass
      if [[ -f "${PROJECT_DIR}/ecosystem.config.cjs" ]]; then
        if pm2 describe "${PM2_APP_NAME}" &>/dev/null; then
          pm2 delete "${PM2_APP_NAME}" || true
        fi
        pm2 start "${PROJECT_DIR}/ecosystem.config.cjs"
        pm2 save
        log_success "PM2 app '${PM2_APP_NAME}' started via ecosystem.config.cjs on 127.0.0.1:${PORT}."
      elif pm2 describe "${PM2_APP_NAME}" &>/dev/null; then
        PORT="${PORT}" NODE_ENV="${NODE_ENV}" HOSTNAME="127.0.0.1" \
          pm2 reload "${PM2_APP_NAME}" --update-env
        log_success "PM2 app '${PM2_APP_NAME}' reloaded on 127.0.0.1:${PORT}."
      else
        log_warn "PM2 app '${PM2_APP_NAME}' not found — starting new instance."
        PORT="${PORT}" NODE_ENV="${NODE_ENV}" HOSTNAME="127.0.0.1" \
          pm2 start npm --name "${PM2_APP_NAME}" -- start -- -H 127.0.0.1 -p "${PORT}"
        pm2 save
        log_success "PM2 app '${PM2_APP_NAME}' started on 127.0.0.1:${PORT} (${DOMAIN})."
      fi
      ;;
    systemd)
      sudo systemctl restart "${SYSTEMD_SERVICE}"
      sleep 2
      if systemctl is-active --quiet "${SYSTEMD_SERVICE}"; then
        log_success "systemd service '${SYSTEMD_SERVICE}' is active."
      else
        die "systemd service '${SYSTEMD_SERVICE}' failed to start. Check: journalctl -u ${SYSTEMD_SERVICE} -n 50"
      fi
      ;;
    none)
      log_warn "PROCESS_MANAGER=none — skipping process restart. Start manually: npm start"
      ;;
    *)
      die "Unknown PROCESS_MANAGER: ${PROCESS_MANAGER}"
      ;;
  esac
}

# ─── Health check ─────────────────────────────────────────────────────────────
verify_deployment() {
  if [[ -z "${HEALTH_CHECK_URL}" ]]; then
    log_warn "Health check skipped (HEALTH_CHECK_URL is empty)."
    return 0
  fi

  log_info "Verifying deployment at ${HEALTH_CHECK_URL}..."

  local attempt=1
  while [[ ${attempt} -le ${HEALTH_CHECK_RETRIES} ]]; do
    if curl -fsS -o /dev/null --max-time 10 "${HEALTH_CHECK_URL}"; then
      log_success "Health check passed (attempt ${attempt}/${HEALTH_CHECK_RETRIES})."
      return 0
    fi
    log_warn "Health check attempt ${attempt}/${HEALTH_CHECK_RETRIES} failed — retrying in ${HEALTH_CHECK_INTERVAL}s..."
    sleep "${HEALTH_CHECK_INTERVAL}"
    attempt=$((attempt + 1))
  done

  die "Health check failed after ${HEALTH_CHECK_RETRIES} attempts: ${HEALTH_CHECK_URL}"
}

# ─── Environment file reminder ────────────────────────────────────────────────
check_env_file() {
  if [[ ! -f "${PROJECT_DIR}/.env" && ! -f "${PROJECT_DIR}/.env.local" && ! -f "${PROJECT_DIR}/.env.production" ]]; then
    log_warn "No .env / .env.local / .env.production found. Ensure environment variables are configured."
  else
    log_success "Environment file detected."
  fi
}

# Prisma cannot migrate until the schema name in DATABASE_URL exists.
ensure_mysql_database() {
  log_info "Ensuring MySQL database customer_profiles exists (root, no password)..."

  if ! command -v mysql &>/dev/null; then
    log_warn "mysql client not found. Create DB manually: mysql -u root -h 127.0.0.1 -e \"CREATE DATABASE IF NOT EXISTS customer_profiles CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\""
    return 0
  fi

  mysql -u root -h 127.0.0.1 --protocol=TCP -e \
    "CREATE DATABASE IF NOT EXISTS \`customer_profiles\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" \
    || die "Could not create database customer_profiles. Confirm MySQL is running on 127.0.0.1:3306 and root has no password (or set MYSQL_PWD)."

  log_success "MySQL database customer_profiles is ready."
}

apply_prisma_migrations() {
  log_info "Applying Prisma migrations..."
  cd "${PROJECT_DIR}"
  npx prisma migrate deploy
  npx prisma generate
  log_success "Prisma schema is up to date."
}

# ─── Main ─────────────────────────────────────────────────────────────────────
main() {
  resolve_paths
  print_banner
  log_info "Deployment started at ${DEPLOY_START_HUMAN}"
  log_info "Building in ${PROJECT_DIR}"

  preflight_checks
  pull_latest_code
  check_env_file
  ensure_mysql_database
  install_dependencies
  apply_prisma_migrations
  build_application
  restart_server
  verify_deployment

  print_summary
}

# Trap errors for clearer failure output
trap 'log_error "Deployment failed at line ${LINENO}. Exit code: $?"; exit 1' ERR

main "$@"
