#!/usr/bin/env bash
# Transactional tooling-only update. Never restarts the active application.
set -Eeuo pipefail
[[ ${EUID} -eq 0 ]] || { echo 'Run this installer with sudo.' >&2; exit 1; }
SOURCE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
exec 9>/run/lock/eusrr-deploy.lock
flock -n 9 || { echo 'A deployment is running. Retry after it finishes.' >&2; exit 3; }
[[ -d /srv/eusrr-slots && ! -L /srv/eusrr-slots ]] || {
  echo 'Expected a real /srv/eusrr-slots directory.' >&2; exit 1;
}
slot_owner="$(stat -c '%u:%g' /srv/eusrr-slots)"
slot_mode="$(stat -c '%a' /srv/eusrr-slots)"
backup="/var/lib/eusrr-deploy/tooling-backup-$(date -u +%Y%m%dT%H%M%SZ)-$$"
install -d -o root -g root -m 0700 "${backup}" "${backup}/before" "${backup}/staged"
staged="${backup}/staged"
installed=()
complete=0
mutated=0

cleanup() {
  local status=$? target name recovered=1
  trap - EXIT HUP INT TERM
  if [[ ${complete} -eq 0 && ${mutated} -eq 1 ]]; then
    set +e
    echo 'Tooling validation failed; restoring the previous files.' >&2
    for target in "${installed[@]}"; do
      name="${target//\//_}"
      if [[ -f ${backup}/before/${name} ]]; then
        cp -a -- "${backup}/before/${name}" "${target}" || recovered=0
      else
        rm -f -- "${target}" || recovered=0
      fi
    done
    chown "${slot_owner}" /srv/eusrr-slots || recovered=0
    chmod "0${slot_mode}" /srv/eusrr-slots || recovered=0
    systemctl daemon-reload || recovered=0
    if [[ ${recovered} -eq 1 ]]; then
      echo "Previous tooling restored. Review backup: ${backup}" >&2
    else
      echo "ERROR: tooling recovery incomplete. Manual recovery required from ${backup}" >&2
    fi
    (( status != 0 )) || status=1
  fi
  exit "${status}"
}
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

# Copy into a root-only directory before checking or installing anything.
for file in eusrr-deploy eusrr-deploy-ssh eusrr-deploy-healthcheck logrotate.conf journald.conf gitea_known_hosts; do
  install -o root -g root -m 0644 "${SOURCE_DIR}/${file}" "${staged}/${file}"
done
for unit in backend frontend celery-worker celery-beat; do
  install -o root -g root -m 0644 "${SOURCE_DIR}/systemd/eusrr-${unit}@.service" \
    "${staged}/eusrr-${unit}@.service"
done
bash -n "${staged}/eusrr-deploy"
bash -n "${staged}/eusrr-deploy-ssh"
python3 -m py_compile "${staged}/eusrr-deploy-healthcheck"
[[ $(ssh-keygen -lf "${staged}/gitea_known_hosts" | awk '{print $2}') == \
  'SHA256:341ON+FsVZMVMsduFUZjevfxjagbFG9yPeZ0edTVSOk' ]] || {
  echo 'Pinned Gitea host key fingerprint does not match.' >&2; exit 1;
}
if ! LC_ALL=C logrotate --debug --state /dev/null "${staged}/logrotate.conf" \
    >"${staged}/logrotate-validation.log" 2>&1 ||
    grep -Eq '^error:|Ignoring .* because' "${staged}/logrotate-validation.log"; then
  cat "${staged}/logrotate-validation.log" >&2
  exit 1
fi
# Ubuntu 24.04 sudo supports anchored argument regexes. The runtime account
# cannot invoke maintenance, self-test, or extra arguments through sudo.
printf '%s\n' 'deploy ALL=(root) NOPASSWD: /usr/local/sbin/eusrr-deploy ^[0-9a-f]{40}$' \
  >"${staged}/sudoers"
visudo -cf "${staged}/sudoers" >/dev/null

install_file() {
  local source="$1" target="$2" mode="$3" name
  name="${target//\//_}"
  [[ ! -L ${target} ]] || { echo "Refusing symlink target: ${target}" >&2; return 1; }
  [[ ! -e ${target} ]] || cp -a -- "${target}" "${backup}/before/${name}"
  installed+=("${target}")
  mutated=1
  install -o root -g root -m "${mode}" "${source}" "${target}.new"
  mv -Tf -- "${target}.new" "${target}"
}

install -d -o root -g root -m 0755 /usr/local/libexec /etc/systemd/journald.conf.d
install_file "${staged}/eusrr-deploy" /usr/local/sbin/eusrr-deploy 0755
install_file "${staged}/eusrr-deploy-ssh" /usr/local/sbin/eusrr-deploy-ssh 0755
install_file "${staged}/eusrr-deploy-healthcheck" /usr/local/libexec/eusrr-deploy-healthcheck 0755
install_file "${staged}/logrotate.conf" /etc/logrotate.d/eusrr-deploy 0644
install_file "${staged}/journald.conf" /etc/systemd/journald.conf.d/60-eusrr-retention.conf 0644
install_file "${staged}/sudoers" /etc/sudoers.d/eusrr-deploy 0440
install_file "${staged}/gitea_known_hosts" /etc/eusrr/gitea_known_hosts 0644
for unit in backend frontend celery-worker celery-beat; do
  install_file "${staged}/eusrr-${unit}@.service" "/etc/systemd/system/eusrr-${unit}@.service" 0644
done
chown root:root /srv/eusrr-slots
# A four-digit chmod retains existing setgid on GNU directory targets.
chmod 00755 /srv/eusrr-slots
systemctl daemon-reload
/usr/local/sbin/eusrr-deploy --self-test
visudo -c >/dev/null
slot="$(cat /var/lib/eusrr-deploy/active-slot)"
[[ ${slot} == blue || ${slot} == green ]] || {
  echo 'Expected a native active slot before updating deployment tooling.' >&2; exit 1;
}
systemctl is-active "eusrr-backend@${slot}.service" "eusrr-frontend@${slot}.service" \
  "eusrr-celery-worker@${slot}.service" "eusrr-celery-beat@${slot}.service"
complete=1
printf 'Deployment tooling and unit templates updated; active application was not restarted. Backup: %s\n' "${backup}"
echo 'Journald limits take effect on its next restart. No logs were vacuumed or releases removed.'
