#!/bin/bash
# ============================================================
# alpha-component — install an optional stack component that the
# installer skipped (the "core" profile leaves out mail, webmail,
# FTP and virtualization).
#
#   alpha-component list
#   alpha-component status <name>
#   alpha-component install <name>     # detached; poll with `log`
#   alpha-component log
#
# It re-runs the SAME provisioning step the installer would have
# run, so there is exactly one implementation of "install mail" and
# no second, drifting copy. Allow-listed: nothing else is runnable.
# ============================================================
set -uo pipefail
umask 022

LOG=/var/log/alpha-component.log
STATE=/run/alpha-component.state

# name → provisioning step
step_for() {
  case "$1" in
    mail)           echo "30-mail" ;;
    webmail)        echo "31-webmail" ;;
    ftp)            echo "40-ftp" ;;
    virtualization) echo "80-virtualization" ;;
    portals)        echo "02-portals" ;;
    *)              echo "" ;;
  esac
}

# name → a file that exists once it is installed
probe_for() {
  case "$1" in
    mail)           echo "/usr/sbin/postfix" ;;
    webmail)        echo "/var/www/webmail" ;;
    ftp)            echo "/usr/sbin/pure-ftpd" ;;
    virtualization) echo "/snap/bin/lxc" ;;
    portals)        echo "/var/www/login-portal" ;;
    *)              echo "" ;;
  esac
}

find_prov() {
  local d
  for d in /opt/alpha-panel/provisioning /opt/alpha-install/provisioning /root/alpha/provisioning; do
    [ -f "$d/bootstrap.sh" ] && { echo "$d"; return 0; }
  done
  return 1
}

ACTION="${1:-}"
NAME="${2:-}"

case "$ACTION" in
  list)
    for n in mail webmail ftp virtualization portals; do
      p="$(probe_for "$n")"
      [ -e "$p" ] && echo "$n installed" || echo "$n missing"
    done
    ;;

  status)
    [ -n "$(step_for "$NAME")" ] || { echo "BAD_COMPONENT"; exit 2; }
    p="$(probe_for "$NAME")"
    if [ -e "$p" ]; then echo "installed"
    elif [ -f "$STATE" ] && [ "$(cat "$STATE" 2>/dev/null)" = "$NAME" ]; then echo "installing"
    else echo "missing"; fi
    ;;

  log)
    tail -n 120 "$LOG" 2>/dev/null || echo "(no log yet)"
    ;;

  install)
    STEP="$(step_for "$NAME")"
    [ -n "$STEP" ] || { echo "BAD_COMPONENT"; exit 2; }
    PROV="$(find_prov)" || { echo "NO_PROVISIONING"; exit 3; }
    [ -f "$PROV/provision.env" ] || { echo "NO_PROVISION_ENV"; exit 3; }
    [ -f "$PROV/steps/$STEP.sh" ] || { echo "NO_STEP: $STEP"; exit 3; }

    # already running?
    if [ -f "$STATE" ] && pgrep -f "bootstrap.sh $STEP" >/dev/null 2>&1; then
      echo "ALREADY_RUNNING"; exit 0
    fi

    printf '%s' "$NAME" > "$STATE"
    {
      printf '\n===== %s : installing %s (step %s) =====\n' "$(date -Is)" "$NAME" "$STEP"
    } >> "$LOG"

    # Detached: an apt install of postfix/dovecot outlives the HTTP request that
    # asked for it, and php-fpm would otherwise kill it when the request ends.
    setsid bash -c "
      cd '$PROV' || exit 1
      DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a NEEDRESTART_SUSPEND=1 \
        ./bootstrap.sh '$STEP' >> '$LOG' 2>&1
      rc=\$?
      printf '===== %s : finished %s rc=%s =====\n' \"\$(date -Is)\" '$NAME' \"\$rc\" >> '$LOG'
      rm -f '$STATE'
    " </dev/null >/dev/null 2>&1 &

    echo "STARTED: $NAME ($STEP)"
    ;;

  *)
    echo "usage: alpha-component {list|status <name>|install <name>|log}"
    exit 1
    ;;
esac
