#!/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:
#   --backup          take the pre-update DB backup
#   --no-backup       skip the pre-update DB backup
#                     (default: DEPLOY_BACKUP, on; --auto: AUTOUPDATE_BACKUP)
#   --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=""; DO_RESTART=1   # DO_BACKUP '' = not given on the command line
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 ;;
        --backup)        DO_BACKUP=1 ;;
        --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"

# Without --backup/--no-backup: --auto (the update path) follows AUTOUPDATE_BACKUP,
# so the knob behaves the same whether invoked manually or by the app-update timer;
# the other modes follow DEPLOY_BACKUP (resolved by lib/deploy.sh).
backup_src=""
if [ -z "$DO_BACKUP" ]; then
    if [ "$MODE" = auto ]; then
        if is_on "$AUTOUPDATE_BACKUP" AUTOUPDATE_BACKUP; then DO_BACKUP=1; else DO_BACKUP=0; fi
        backup_src="AUTOUPDATE_BACKUP=$AUTOUPDATE_BACKUP"
    else
        backup_src="DEPLOY_BACKUP=$DEPLOY_BACKUP"
    fi
fi
. "$SCRIPT_DIR/lib/deploy.sh"
case "$MODE" in version|snapshot|activate|auto)
    if [ "$DO_BACKUP" -eq 0 ] && [ -n "$backup_src" ]; then
        de_log "$backup_src — skipping the pre-update backup (use --backup to take one)"
    fi ;;
esac

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."
