#!/bin/sh
set -eu

APP_DIR="${SUITECRM_APP_DIR:?SUITECRM_APP_DIR must be baked into the image}"
WEB_USER="${SUITECRM_WEB_USER:?SUITECRM_WEB_USER must be baked into the image}"
WEB_GROUP="${SUITECRM_WEB_GROUP:?SUITECRM_WEB_GROUP must be baked into the image}"
INSTALL_FLAG="${APP_DIR}/public/installed.flag"
SEED_DIR="${SUITECRM_SEED_DIR:?SUITECRM_SEED_DIR must be baked into the image}"
APP_VERSION="${SUITECRM_APP_VERSION:?SUITECRM_APP_VERSION must be baked into the image}"
SEED_STAMP="${APP_DIR}/.tree-seeded"

log() { printf '%s %s\n' "[suitecrm-entrypoint]" "$*" >&2; }

if [ ! -d "$APP_DIR" ]; then
  log "ERROR: Application directory '$APP_DIR' does not exist."
  exit 1
fi

if [ -n "${SUITECRM_SAML_IDP_DESCRIPTOR_URL:-}" ]; then
  log "Fetching the IdP signing certificate from ${SUITECRM_SAML_IDP_DESCRIPTOR_URL}..."
  _descriptor=$(curl -fsS --connect-timeout 20 --max-time 25 --retry 20 --retry-all-errors --retry-delay 5 --proxy "${SUITECRM_OIDC_SOCKS_PROXY:-}" "$SUITECRM_SAML_IDP_DESCRIPTOR_URL")
  _tags=$(printf '%s' "$_descriptor" | tr '<' '\n')
  SAML_IDP_X509CERT=$(printf '%s' "$_tags" | awk -F'>' '/KeyDescriptor[^>]*use="signing"/ { s=1 } s && $1 ~ /X509Certificate$/ && $2 != "" { print $2; exit }')
  if [ -z "$SAML_IDP_X509CERT" ]; then
    SAML_IDP_X509CERT=$(printf '%s' "$_tags" | awk -F'>' '$1 ~ /X509Certificate$/ && $2 != "" { print $2; exit }')
  fi
  if [ -z "$SAML_IDP_X509CERT" ]; then
    log "ERROR: no X509Certificate in the IdP descriptor."
    exit 1
  fi
  export SAML_IDP_X509CERT
  log "IdP certificate loaded."
fi

TMPDIR="${APP_DIR}/tmp"
export TMPDIR
mkdir -p "$TMPDIR"
chown "$WEB_USER:$WEB_GROUP" "$TMPDIR"
chmod 775 "$TMPDIR"

BOOT_LOCK="${APP_DIR}/.suitecrm-boot.lock.d"

_have_lock=0
_lock_tries=0
while :; do
  if mkdir "$BOOT_LOCK" 2>/dev/null; then
    _have_lock=1
    break
  fi
  # Exception: 1800s exceeds the orchestrator kill ceiling (start_period 20m
  # plus retries), so only a dead leader's lock can be this old.
  _lock_mtime=$(stat -c %Y "$BOOT_LOCK" 2>/dev/null || echo 0)
  if [ "$_lock_mtime" -gt 0 ] && [ $(($(date +%s) - _lock_mtime)) -ge 1800 ]; then
    log "Stale boot lock detected - removing it and retrying."
    rmdir "$BOOT_LOCK" 2>/dev/null || true  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error
  fi
  if [ -f "$INSTALL_FLAG" ]; then
    break
  fi
  _lock_tries=$((_lock_tries + 1))
  if [ "$_lock_tries" -ge 420 ]; then
    log "ERROR: timed out waiting for the boot lock or install flag."
    exit 1
  fi
  sleep 5
done

if [ "$_have_lock" = "1" ]; then
  trap 'rmdir "$BOOT_LOCK" 2>/dev/null || true' EXIT
  trap 'rmdir "$BOOT_LOCK" 2>/dev/null || true; exit 143' TERM INT  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error

  if [ ! -f "$SEED_STAMP" ]; then
    if [ -f "$INSTALL_FLAG" ]; then
      log "Installed volume without seed stamp - marking as seeded, keeping the live tree."
    else
      log "Seeding SuiteCRM tree from ${SEED_DIR} into ${APP_DIR}..."
      cp -a "${SEED_DIR}/." "${APP_DIR}/"
      log "Seed complete."
    fi
    echo "$APP_VERSION" > "$SEED_STAMP"
    chown "$WEB_USER:$WEB_GROUP" "$SEED_STAMP"
  else
    _seeded_version=$(cat "$SEED_STAMP")
    if [ "$_seeded_version" = "seeded" ]; then
      echo "$APP_VERSION" > "$SEED_STAMP"
    elif [ "$_seeded_version" != "$APP_VERSION" ]; then
      log "WARNING: volume tree is ${_seeded_version}, image ships ${APP_VERSION} - the tree is NOT re-seeded, upgrade it manually."
    fi
  fi

  CACHE_REFRESH=0
  if [ ! -f "$INSTALL_FLAG" ]; then
    CACHE_REFRESH=1
    log "SuiteCRM 8 is not installed - performing automated installation..."

    php bin/console suitecrm:app:install \
        -u "$SUITECRM_ADMIN_USERNAME" \
        -p "$SUITECRM_ADMIN_PASSWORD" \
        -U "$SUITECRM_DB_USER" \
        -P "$SUITECRM_DB_PASSWORD" \
        -H "$SUITECRM_DB_HOST" \
        -Z "$SUITECRM_DB_PORT" \
        -N "$SUITECRM_DB_NAME" \
        -S "$SUITECRM_URL" \
        -d "no"

    echo "installed" > "$INSTALL_FLAG"
    chown "$WEB_USER:$WEB_GROUP" "$INSTALL_FLAG"

    log "SuiteCRM installation completed successfully."
  else
    log "SuiteCRM already installed - skipping installer."
  fi

  if [ -d "${APP_DIR}/cache/prod" ] && [ -n "$(find "${APP_DIR}/extensions" -path '*/config/*' -type f -newer "${APP_DIR}/cache/prod" -print -quit)" ]; then
    CACHE_REFRESH=1
    log "Extension config is newer than the prod cache - refreshing it."
  fi

  if [ "$CACHE_REFRESH" = "1" ] || [ ! -d "${APP_DIR}/cache/prod" ]; then
    log "Clearing Symfony cache..."
    php bin/console cache:clear --no-warmup || true  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error
    php bin/console cache:warmup || true  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error
  else
    log "Existing prod cache - skipping cache:clear/warmup."
  fi

  if [ "$CACHE_REFRESH" = "1" ]; then
    chown -R "$WEB_USER:$WEB_GROUP" "${APP_DIR}/public/legacy"
  fi

  # Exception: install/cache:clear above run as root; the legacy language
  # caches they wipe are regenerated lazily by apache as www-data, which
  # cannot write into root-owned cache dirs -> permanent 500 without this.
  chown -R "$WEB_USER:$WEB_GROUP" "${APP_DIR}/cache" "${APP_DIR}/public/legacy/cache" 2>/dev/null || true  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error

  chown -R "$WEB_USER:$WEB_GROUP" "${APP_DIR}/logs"

  rmdir "$BOOT_LOCK" 2>/dev/null || true  # nocheck: shell-or-true -- grandfathered: worked in practice; TODO: sharpen to catch only the exact tolerated error
  trap - EXIT TERM INT
else
  log "SuiteCRM installed by another replica - skipping installer and cache pass."
fi

log "Starting $*..."
exec "$@"
