#!/bin/bash
set -euo pipefail
umask 022

export NODE_OPTIONS="--max_old_space_size=4096"
export CI="true"
export npm_config_progress="false"
export npm_config_loglevel="warn"
export FORCE_COLOR="0"

LOG_FILE="/var/log/bssapp_deploy.log"
APP_DIR="/opt/bssapp"
LOCK_FILE="/tmp/bssapp_deploy.lock"
RUNTIME_BACKUP_DIR=""
RUNTIME_PRESERVE_FILES=(
  ".env"
  "mail.env"
  "svc/.env"
  "svc/mail.env"
  "svc/fonts"
  "svc/public"
  "deploy/deploy.sh"
  "scripts/deploy.sh"
)

log_step() {
  echo "== $1 =="
}

backup_runtime_files() {
  RUNTIME_BACKUP_DIR="$(mktemp -d /tmp/bssapp-runtime.XXXXXX)"

  for rel in "${RUNTIME_PRESERVE_FILES[@]}"; do
    src="$APP_DIR/$rel"
    dst="$RUNTIME_BACKUP_DIR/$rel"
    if [[ -e "$src" ]]; then
      mkdir -p "$(dirname "$dst")"
      cp -a "$src" "$dst"
    fi
  done
}

restore_runtime_files() {
  [[ -n "$RUNTIME_BACKUP_DIR" && -d "$RUNTIME_BACKUP_DIR" ]] || return 0
  find "$RUNTIME_BACKUP_DIR" -mindepth 1 -print -quit | grep -q . || return 0
  cp -a "$RUNTIME_BACKUP_DIR/." "$APP_DIR/"
}

cleanup_runtime_backup() {
  if [[ -n "$RUNTIME_BACKUP_DIR" && -d "$RUNTIME_BACKUP_DIR" ]]; then
    rm -rf "$RUNTIME_BACKUP_DIR"
  fi
}

ensure_runtime_env_files() {
  [[ -f "$APP_DIR/.env" ]] || touch "$APP_DIR/.env"
  [[ -f "$APP_DIR/mail.env" ]] || touch "$APP_DIR/mail.env"
  [[ -f "$APP_DIR/svc/.env" ]] || touch "$APP_DIR/svc/.env"
  [[ -f "$APP_DIR/svc/mail.env" ]] || touch "$APP_DIR/svc/mail.env"
}

ensure_pdf_fonts() {
  local font_dir="$APP_DIR/svc/fonts"
  local sys_font_dir="/usr/share/fonts/truetype/dejavu"

  mkdir -p "$font_dir"

  if [[ ! -f "$font_dir/DejaVuSans.ttf" && -f "$sys_font_dir/DejaVuSans.ttf" ]]; then
    cp -a "$sys_font_dir/DejaVuSans.ttf" "$font_dir/DejaVuSans.ttf"
  fi
  if [[ ! -f "$font_dir/DejaVuSans-Bold.ttf" && -f "$sys_font_dir/DejaVuSans-Bold.ttf" ]]; then
    cp -a "$sys_font_dir/DejaVuSans-Bold.ttf" "$font_dir/DejaVuSans-Bold.ttf"
  fi

  if [[ ! -f "$font_dir/DejaVuSans.ttf" || ! -f "$font_dir/DejaVuSans-Bold.ttf" ]]; then
    echo "ERROR: Required PDF fonts missing in $font_dir"
    return 1
  fi
}

ensure_ui_permissions() {
  local ui_root="$APP_DIR/ui/dist/spa"

  if [[ ! -d "$ui_root" ]]; then
    echo "ERROR: UI build output not found at $ui_root"
    return 1
  fi

  chmod 755 /opt "$APP_DIR" "$APP_DIR/ui" "$APP_DIR/ui/dist" "$ui_root"
  find "$ui_root" -type d -exec chmod 755 {} \;
  find "$ui_root" -type f -exec chmod 644 {} \;
}

clean_ui_build_artifacts() {
  cd "$APP_DIR/ui"
  # dist'i silmiyoruz -> eski chunklar kısa süre kalabilir, ChunkLoadError azalır
  rm -rf .quasar node_modules/.cache || true
}

purge_nginx_ui_cache() {
  rm -rf /var/cache/nginx/* || true
}

purge_cdn_html_cache() {
  local zone_id="${CF_ZONE_ID:-}"
  local api_token="${CF_API_TOKEN:-}"
  local site_url="${SITE_URL:-https://ss.baggi.com.tr}"
  local purge_urls="${CDN_PURGE_URLS:-$site_url/,$site_url/index.html}"

  if [[ -z "$zone_id" || -z "$api_token" ]]; then
    echo "CDN purge skipped: CF_ZONE_ID / CF_API_TOKEN not set."
    return 0
  fi

  IFS=',' read -r -a url_array <<< "$purge_urls"
  if [[ ${#url_array[@]} -eq 0 ]]; then
    echo "CDN purge skipped: no URLs configured."
    return 0
  fi

  local files_json=""
  local sep=""
  local url=""
  for raw in "${url_array[@]}"; do
    url="$(echo "$raw" | xargs)"
    [[ -n "$url" ]] || continue
    files_json="${files_json}${sep}\"${url}\""
    sep=","
  done

  if [[ -z "$files_json" ]]; then
    echo "CDN purge skipped: URL list resolved to empty."
    return 0
  fi

  local payload
  payload="{\"files\":[${files_json}]}"

  local response
  response="$(curl -sS -X POST "https://api.cloudflare.com/client/v4/zones/${zone_id}/purge_cache" \
    -H "Authorization: Bearer ${api_token}" \
    -H "Content-Type: application/json" \
    --data "$payload" || true)"

  if echo "$response" | grep -q '"success":true'; then
    echo "CDN HTML purge completed."
    return 0
  fi

  echo "WARN: CDN purge may have failed. Response: $response"
  return 0
}

extract_app_js_name() {
  local source="$1"
  echo "$source" | grep -oE 'app\.[a-f0-9]+\.js' | head -n1 || true
}

verify_live_ui_hash() {
  local site_url="${SITE_URL:-https://ss.baggi.com.tr}"
  local fail_on_mismatch="${FAIL_ON_UI_HASH_MISMATCH:-false}"
  local local_index="$APP_DIR/ui/dist/spa/index.html"

  if [[ ! -f "$local_index" ]]; then
    echo "WARN: local index not found for hash verify: $local_index"
    return 0
  fi

  local local_app
  local_app="$(extract_app_js_name "$(cat "$local_index")")"
  if [[ -z "$local_app" ]]; then
    echo "WARN: local app hash parse failed."
    return 0
  fi

  local live_html
  live_html="$(curl -sS -H "Cache-Control: no-cache" -H "Pragma: no-cache" "${site_url}/" || true)"
  if [[ -z "$live_html" ]]; then
    echo "WARN: live index fetch failed for ${site_url}/"
    return 0
  fi

  local live_app
  live_app="$(extract_app_js_name "$live_html")"
  if [[ -z "$live_app" ]]; then
    echo "WARN: live app hash parse failed."
    return 0
  fi

  if [[ "$local_app" == "$live_app" ]]; then
    echo "UI HASH OK: ${local_app}"
    return 0
  fi

  echo "WARN: UI hash mismatch local=${local_app} live=${live_app}"
  if [[ "$fail_on_mismatch" == "true" ]]; then
    echo "ERROR: FAIL_ON_UI_HASH_MISMATCH=true and UI hash mismatch detected."
    return 1
  fi
  return 0
}

ensure_ui_readable_by_nginx() {
  local ui_index="$APP_DIR/ui/dist/spa/index.html"

  if [[ ! -f "$ui_index" ]]; then
    echo "ERROR: UI index not found at $ui_index"
    return 1
  fi

  if id -u www-data >/dev/null 2>&1; then
    if ! su -s /bin/sh -c "test -r '$ui_index'" www-data; then
      echo "ERROR: www-data cannot read $ui_index"
      namei -l "$ui_index" || true
      return 1
    fi
  fi
}

ensure_node20_for_ui_build() {
  local required_major=20
  local nvm_dir="${NVM_DIR:-$HOME/.nvm}"

  if [[ -s "$nvm_dir/nvm.sh" ]]; then
    # shellcheck disable=SC1090
    source "$nvm_dir/nvm.sh"
    nvm install "$required_major" >/dev/null
    nvm use "$required_major" >/dev/null
  fi

  if ! command -v node >/dev/null 2>&1; then
    echo "ERROR: node command not found"
    return 1
  fi

  local node_version
  node_version="$(node -v 2>/dev/null || true)"
  local node_major
  node_major="$(echo "$node_version" | sed -E 's/^v([0-9]+).*/\1/')"

  if [[ -z "$node_major" || "$node_major" -lt "$required_major" ]]; then
    echo "ERROR: Node.js >=${required_major} required for UI build. Current: ${node_version:-unknown}"
    echo "Hint: install nvm and run: nvm install ${required_major} && nvm alias default ${required_major}"
    return 1
  fi

  echo "UI build runtime: node=$node_version npm=$(npm -v)"
}

build_api_binary() {
  if ! command -v go >/dev/null 2>&1; then
    echo "ERROR: go command not found"
    return 1
  fi

  export GOPATH="${GOPATH:-/var/cache/bssapp-go}"
  export GOMODCACHE="${GOMODCACHE:-$GOPATH/pkg/mod}"
  export GOCACHE="${GOCACHE:-/var/cache/bssapp-go-build}"
  mkdir -p "$GOPATH" "$GOMODCACHE" "$GOCACHE"

  cd "$APP_DIR/svc"
  GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o "$APP_DIR/svc/bssapp" ./main.go
  chmod +x "$APP_DIR/svc/bssapp"
}

restart_services() {
  systemctl daemon-reload || true

  systemctl restart bssapp
  if ! systemctl is-active --quiet bssapp; then
    echo "ERROR: bssapp service failed to start"
    return 1
  fi

  if systemctl cat nginx >/dev/null 2>&1; then
    if ! nginx -t; then
      echo "ERROR: nginx config test failed"
      return 1
    fi
    systemctl reload nginx
    if ! systemctl is-active --quiet nginx; then
      echo "ERROR: nginx service failed to start"
      return 1
    fi
  else
    echo "WARN: nginx service not found; frontend may be unreachable."
  fi
}

run_deploy() {
  trap cleanup_runtime_backup EXIT

  exec 9>"$LOCK_FILE"
  if ! flock -n 9; then
    echo "[$(date '+%F %T')] Deploy already running. Skipping new request."
    return 0
  fi

  echo "=============================="
  echo "[DEPLOY START] $(date '+%F %T')"
  echo "=============================="

  cd "$APP_DIR"

  log_step "GIT SYNC"
  backup_runtime_files
  git fetch origin
  git reset --hard origin/master
  git clean -fdx \
    -e .env \
    -e mail.env \
    -e svc/.env \
    -e svc/mail.env \
    -e svc/fonts \
    -e svc/public \
    -e deploy/deploy.sh \
    -e scripts/deploy.sh \
    -e svc/bssapp
  restore_runtime_files
  echo "DEPLOY COMMIT: $(git rev-parse --short HEAD)"

  log_step "BUILD UI"
  cd "$APP_DIR/ui"
  ensure_node20_for_ui_build
  clean_ui_build_artifacts
  npm ci --no-audit --no-fund --include=optional
  npm i -D --no-audit --no-fund sass-embedded@1.93.2
  npm run build

  log_step "ENSURE UI PERMISSIONS"
  ensure_ui_permissions
  ensure_ui_readable_by_nginx

  log_step "BUILD API"
  build_api_binary

  log_step "ENSURE ENV FILES"
  ensure_runtime_env_files

  log_step "ENSURE PDF FONTS"
  ensure_pdf_fonts

  log_step "RESTART SERVICES"
  restart_services

  log_step "PURGE NGINX CACHE"
  purge_nginx_ui_cache

  log_step "PURGE CDN HTML CACHE (OPTIONAL)"
  purge_cdn_html_cache

  log_step "VERIFY LIVE UI HASH"
  verify_live_ui_hash

  echo "[DEPLOY FINISHED] $(date '+%F %T')"
}

if [[ "${1:-}" == "--run" ]]; then
  mkdir -p "$(dirname "$LOG_FILE")"
  if command -v logger >/dev/null 2>&1; then
    run_deploy 2>&1 | tee -a "$LOG_FILE" >(logger -t bssapp-deploy -p user.info)
    exit ${PIPESTATUS[0]}
  else
    run_deploy >>"$LOG_FILE" 2>&1
    exit $?
  fi
fi

nohup /bin/bash "$0" --run </dev/null >/dev/null 2>&1 &
exit 0
