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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
INSTALL_ROOT="${ERP_INSTALL_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd -P)}"
CONFIG_FILE="${ERP_CONFIG_FILE:-$INSTALL_ROOT/config/erp.env}"

say() { printf '[ERP] %s\n' "$*"; }
fail() { printf '[ERP] ERROR: %s\n' "$*" >&2; exit 1; }

migrate_legacy_update_source() {
  local legacy_url='http://38.76.196.225:10099'
  local official_url='https://git.awaioi.com'
  local configured_url="${OA_UPDATE_GITEA_BASE_URL:-}"
  [[ "${configured_url%/}" == "$legacy_url" ]] || return 0

  local temporary
  temporary="$(mktemp "${CONFIG_FILE}.migration.XXXXXX")" \
    || fail 'unable to create the update-source migration file'
  if awk -v official_url="$official_url" '
    BEGIN { base_url_written = 0; insecure_written = 0 }
    /^OA_UPDATE_GITEA_BASE_URL=/ {
      if (!base_url_written) print "OA_UPDATE_GITEA_BASE_URL=\047" official_url "\047"
      base_url_written = 1
      next
    }
    /^OA_UPDATE_ALLOW_INSECURE_HTTP=/ {
      if (!insecure_written) print "OA_UPDATE_ALLOW_INSECURE_HTTP=\047false\047"
      insecure_written = 1
      next
    }
    { print }
    END {
      if (!base_url_written) print "OA_UPDATE_GITEA_BASE_URL=\047" official_url "\047"
      if (!insecure_written) print "OA_UPDATE_ALLOW_INSECURE_HTTP=\047false\047"
    }
  ' "$CONFIG_FILE" > "$temporary" && chmod 600 "$temporary" && mv -f "$temporary" "$CONFIG_FILE"; then
    say "Update source migrated to $official_url"
  else
    rm -f "$temporary"
    say "WARNING: could not persist the update source migration; using $official_url for this process"
  fi

  OA_UPDATE_GITEA_BASE_URL="$official_url"
  OA_UPDATE_ALLOW_INSECURE_HTTP=false
  export OA_UPDATE_GITEA_BASE_URL OA_UPDATE_ALLOW_INSECURE_HTTP
}

load_configuration() {
  [[ -r "$CONFIG_FILE" ]] || fail "configuration not readable: $CONFIG_FILE"
  set -a
  # The installer writes this file with POSIX shell-safe single-quoted values.
  # shellcheck disable=SC1090
  source "$CONFIG_FILE"
  set +a
  migrate_legacy_update_source

  RUN_DIR="${ERP_RUN_DIR:-$INSTALL_ROOT/run}"
  JAR_PATH="${ERP_JAR_PATH:-$INSTALL_ROOT/current/app/kaidi-erp.jar}"
  INSTALLER_JAR="${ERP_INSTALLER_JAR:-$INSTALL_ROOT/installer/kaidi-erp-installer.jar}"
  PENDING_FILE="${ERP_INSTALL_PENDING_FILE:-$INSTALL_ROOT/state/install.pending}"
  INSTALL_LOCK_FILE="${ERP_INSTALL_LOCK_FILE:-$INSTALL_ROOT/state/install.lock}"
  INSTALL_LOG_FILE="${ERP_INSTALL_LOG_FILE:-$(dirname "$PENDING_FILE")/install-formal.log}"
  HEALTH_URL="${ERP_HEALTH_URL:-http://127.0.0.1:${SERVER_PORT:-8091}/api/oa/health}"
  HEALTH_TIMEOUT_SECONDS="${ERP_INSTALL_HEALTH_TIMEOUT_SECONDS:-240}"
  HEALTH_POLL_SECONDS="${ERP_UPDATE_HEALTH_POLL_SECONDS:-2}"
}

resolve_java() {
  JAVA_BIN="${ERP_JAVA_BIN:-}"
  if [[ -z "$JAVA_BIN" ]]; then
    if [[ -n "${JAVA_HOME:-}" && -x "$JAVA_HOME/bin/java" ]]; then
      JAVA_BIN="$JAVA_HOME/bin/java"
    else
      JAVA_BIN="$(command -v java || true)"
    fi
  fi
  [[ -n "$JAVA_BIN" && -x "$JAVA_BIN" ]] || fail 'Java 17+ is not installed'
  local java_major
  java_major="$("$JAVA_BIN" -version 2>&1 | awk -F'[".]' '/version/ {print $2; exit}')"
  [[ "$java_major" =~ ^[0-9]+$ && "$java_major" -ge 17 ]] || fail 'Java 17+ is required'
}

split_java_options() {
  IFS=$' \t' read -r -a JAVA_OPTS <<< "${ERP_JAVA_OPTS:--Xms512m -Xmx2g}"
  IFS=$' \t' read -r -a INSTALLER_JAVA_OPTS <<< "${ERP_INSTALLER_JAVA_OPTS:--Xms128m -Xmx512m}"
}

write_pid() {
  mkdir -p "$RUN_DIR"
  printf '%s\n' "$1" > "$RUN_DIR/app.pid"
}

clear_pid() {
  local expected="$1"
  if [[ -r "$RUN_DIR/app.pid" && "$(<"$RUN_DIR/app.pid")" == "$expected" ]]; then
    rm -f "$RUN_DIR/app.pid"
  fi
}

run_formal_application_direct() {
  [[ -r "$JAR_PATH" ]] || fail "application jar not readable: $JAR_PATH"
  write_pid "$$"
  exec "$JAVA_BIN" "${JAVA_OPTS[@]}" \
    -jar "$JAR_PATH" \
    --spring.profiles.active=postgres \
    --server.port="${SERVER_PORT:-8091}"
}

run_web_installer() {
  [[ -r "$INSTALLER_JAR" ]] || fail "installer jar not readable: $INSTALLER_JAR"
  say "Starting first-run installer on port ${SERVER_PORT:-8091}"
  printf '%s\n' "$$" > "$RUN_DIR/installer.pid"
  set +e
  "$JAVA_BIN" "${INSTALLER_JAVA_OPTS[@]}" \
    -jar "$INSTALLER_JAR" \
    --server.port="${SERVER_PORT:-8091}"
  local status=$?
  set -e
  rm -f "$RUN_DIR/installer.pid"
  [[ "$status" == "0" ]] || fail "web installer exited with status $status"
  [[ -f "$PENDING_FILE" ]] || fail 'web installer exited before installation was completed'
}

finalize_installation() {
  [[ -f "$PENDING_FILE" ]] || fail "pending installation marker is missing: $PENDING_FILE"
  [[ ! -e "$INSTALL_LOCK_FILE" ]] || fail "installation lock already exists: $INSTALL_LOCK_FILE"
  mkdir -p "$(dirname "$INSTALL_LOCK_FILE")"
  mv "$PENDING_FILE" "$INSTALL_LOCK_FILE"
  chmod 600 "$INSTALL_LOCK_FILE"
  rm -rf "$INSTALL_ROOT/installer"
  say "Installation lock written; the web installer has been removed"
}

run_pending_formal_application() {
  [[ -r "$JAR_PATH" ]] || fail "application jar not readable: $JAR_PATH"
  [[ "$HEALTH_TIMEOUT_SECONDS" =~ ^[1-9][0-9]*$ ]] || fail 'invalid installation health timeout'
  [[ "$HEALTH_POLL_SECONDS" =~ ^[1-9][0-9]*$ ]] || fail 'invalid health poll interval'

  say 'Starting the formal PostgreSQL application'
  mkdir -p "$(dirname "$INSTALL_LOG_FILE")"
  : > "$INSTALL_LOG_FILE"
  chmod 600 "$INSTALL_LOG_FILE"
  "$JAVA_BIN" "${JAVA_OPTS[@]}" \
    -jar "$JAR_PATH" \
    --spring.profiles.active=postgres \
    --server.port="${SERVER_PORT:-8091}" \
    > >(tee -a "$INSTALL_LOG_FILE") 2>&1 &
  APP_PID=$!
  write_pid "$APP_PID"

  forward_signal() {
    kill -TERM "$APP_PID" 2>/dev/null || true
  }
  trap forward_signal TERM INT

  local deadline=$((SECONDS + HEALTH_TIMEOUT_SECONDS))
  while (( SECONDS < deadline )); do
    if ! kill -0 "$APP_PID" 2>/dev/null; then
      set +e
      wait "$APP_PID"
      local status=$?
      set -e
      clear_pid "$APP_PID"
      say "Formal application diagnostics: $INSTALL_LOG_FILE"
      fail "formal application exited before becoming healthy (status $status)"
    fi
    if curl -fsS --connect-timeout 2 --max-time 5 "$HEALTH_URL" >/dev/null 2>&1; then
      finalize_installation
      set +e
      wait "$APP_PID"
      local status=$?
      set -e
      clear_pid "$APP_PID"
      return "$status"
    fi
    sleep "$HEALTH_POLL_SECONDS"
  done

  kill -TERM "$APP_PID" 2>/dev/null || true
  set +e
  wait "$APP_PID"
  set -e
  clear_pid "$APP_PID"
  say "Formal application diagnostics: $INSTALL_LOG_FILE"
  fail "formal application did not become healthy within ${HEALTH_TIMEOUT_SECONDS} seconds"
}

main() {
  load_configuration
  resolve_java
  split_java_options
  mkdir -p "$RUN_DIR"

  if [[ -f "$INSTALL_LOCK_FILE" ]]; then
    run_formal_application_direct
  fi

  if [[ ! -f "$PENDING_FILE" ]]; then
    run_web_installer
    load_configuration
    resolve_java
    split_java_options
  fi

  run_pending_formal_application
}

main "$@"
