#!/usr/bin/env bash
# app-deploy — install/activate a release: stop → (backup) → activate → start.
#
# This is the deployment engine's stock deploy CLI. It is a thin wrapper over
# lib/deploy.sh; an app with a non-standard shape can write its own CLI that
# sources common.sh + lib/deploy.sh and composes the same functions.
#
# Modes:
#   app-deploy <version>           download+verify+deploy that release version
#   app-deploy --auto              deploy the target version (if changed). Source:
#                                  CSC account configured -> the instance's
#                                  confirmed version (signed); else VERSION_URL/CHANNEL
#   app-deploy --snapshot [--id n] download+deploy the snapshot from SNAPSHOT_URL
#   app-deploy --activate <id>     switch to an already-staged release (manual)
#   app-deploy --list              list staged releases (and the active one)
#   app-deploy --show-config       print resolved configuration
# Options:
#   --no-backup       skip the pre-update DB backup (default: take one)
#   --no-restart      stage+activate only (do not stop/start the service)
#   --channel <c>     override the --auto public channel
#   --config <path>   use a specific config file
#   -h, --help
#
# A DEPLOY_HOOK runs after staging and BEFORE activation, for site/product
# customizations (a non-zero exit aborts the deploy).
#
# Switching to an OLDER release is NOT a safe rollback: schema migrations run
# forward on startup. Restore a matching DB backup first.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# help = the header comment block above, printed until the first non-# line. The
# generic command names (app-deploy, …) are rewritten to THIS script's own name,
# so a renamed <product>-deploy — or a custom CLI sourcing the libs — prints its
# own name with no install-time edit. pfx='app' (a no-op) when not renamed.
usage() {
    local cmd pfx; cmd="$(basename -- "$0")"; pfx="${cmd%-deploy}"
    sed -n '2,${/^#/!q;s/^# \{0,1\}//;s/^#$//;p}' "$0" \
        | sed -E "s/app-(deploy|backup|health|update)/$pfx-\1/g"
}

MODE=""; VERSION=""; REL_ID=""; ACT_ID=""
DO_BACKUP=1; DO_RESTART=1
while [ $# -gt 0 ]; do
    case "$1" in
        --auto)          MODE=auto ;;
        --snapshot)      MODE=snapshot ;;
        --id)            REL_ID="$2"; shift ;;
        --id=*)          REL_ID="${1#*=}" ;;
        --activate)      MODE=activate; ACT_ID="$2"; shift ;;
        --activate=*)    MODE=activate; ACT_ID="${1#*=}" ;;
        --list)          MODE=list ;;
        --show-config)   MODE=showconfig ;;
        --no-backup)     DO_BACKUP=0 ;;
        --no-restart)    DO_RESTART=0 ;;
        --channel)       CHANNEL="$2"; shift ;;
        --channel=*)     CHANNEL="${1#*=}" ;;
        --config)        CONFIG_FILE="$2"; shift ;;
        --config=*)      CONFIG_FILE="${1#*=}" ;;
        -h|--help)       usage; exit 0 ;;
        -*)              echo "Unknown option: $1" >&2; exit 2 ;;
        *)               if [ -z "$MODE" ]; then MODE=version; VERSION="$1";
                         else echo "Unexpected argument: $1" >&2; exit 2; fi ;;
    esac
    shift
done
[ -n "$MODE" ] || { usage; exit 2; }

. "$SCRIPT_DIR/common.sh"
. "$SCRIPT_DIR/lib/deploy.sh"

# --auto is the update path: honor AUTOUPDATE_BACKUP=off there (typical for test
# instances), so the knob behaves the same whether invoked manually or by the
# app-update timer. Explicit modes always back up unless --no-backup is given.
if [ "$MODE" = auto ] && [ "$DO_BACKUP" -eq 1 ] && ! is_on "$AUTOUPDATE_BACKUP" AUTOUPDATE_BACKUP; then
    DO_BACKUP=0
    de_log "AUTOUPDATE_BACKUP=off — --auto skips the pre-update backup"
fi

case "$MODE" in
    showconfig) de_show_config; exit 0 ;;
    list)       cmd_list; exit 0 ;;
    activate)   [ -n "$ACT_ID" ] || de_die "--activate needs an id"
                acquire_deploy_lock; deploy "$ACT_ID" ;;
    version)    acquire_deploy_lock
                stage_version "$VERSION"; deploy "$STAGED_ID" ;;
    snapshot)   acquire_deploy_lock
                stage_snapshot "$REL_ID"; deploy "$STAGED_ID" ;;
    # stage_version/resolve_auto_version are called DIRECTLY (not in $(...)): a
    # failed download/version-fetch de_dies and aborts here, instead of the exit
    # being swallowed by a command substitution and the deploy blundering on.
    auto)       resolve_auto_version; cur="$(active_id)"
                if csc_enabled; then src="$(csc_confirmed_version_url)"; else src="${VERSION_URL%/}/$CHANNEL"; fi
                de_log "Target version $src -> $AUTO_VERSION (active: $cur)"
                if [ "$AUTO_VERSION" = "$cur" ]; then de_log "Already up to date."; exit 0; fi
                acquire_deploy_lock
                stage_version "$AUTO_VERSION"; deploy "$STAGED_ID" ;;
    *)          de_die "internal: unknown mode '$MODE'" ;;
esac
de_log "Done."
