#!/usr/bin/env bash
# Take a server back to how it was before install.sh: the product, its
# instances and images, then norsk-ctl itself with everything its installer put
# on the box. Docker and anything else the box already had stay.
#
#   bash uninstall.sh [--keep-ctl | --remove-ctl] [--yes]
#
# Runs from the release directory (release.env names the product). norsk-ctl is
# removed only when install.sh installed it (its baseline record says so) or no
# record exists, and never while another product is still registered.
# --keep-ctl removes only this product; --remove-ctl removes norsk-ctl even
# though it was there before install.sh.
#
# Ends by listing anything left behind, and exits non-zero if there is any.
#
# Copied verbatim from @norskvideo/ctl-dev-kit conventions/server-uninstall.sh
# and drift-gated: edit the dev-kit source and re-sync, never this copy.
set -euo pipefail

info() { printf '\n==> %s\n' "$*"; }
oops() {
  printf 'error: %s\n' "$*" >&2
  exit 1
}
ctl() {
  sudo -u norsk env NORSK_CTL_CONFIG_DIR=/etc/norsk-ctl NORSK_CTL_STATE_DIR=/var/lib/norsk-ctl \
    NORSK_CTL_LOG_DIR=/var/log/norsk-ctl norsk-ctl "$@"
}
have_ctl() { command -v norsk-ctl >/dev/null && systemctl is-active --quiet norsk-ctl; }

# Whether ctl goes too: asked to keep it, or it predates install.sh and nobody
# asked for it gone.
removes_ctl() {
  local keep=$1 remove=$2 preinstalled=$3
  [ "${keep}" = 1 ] && return 1
  [ "${preinstalled}" = 1 ] && [ "${remove}" != 1 ] && return 1
  return 0
}

main() {
  local here
  here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  # shellcheck source=/dev/null
  . "${here}/release.env" # PRODUCT, IMAGE
  local keep_ctl=0 remove_ctl_flag=0 assume_yes=0
  while [ $# -gt 0 ]; do
    case "$1" in
      --keep-ctl) keep_ctl=1 ;;
      --remove-ctl) remove_ctl_flag=1 ;;
      --yes | -y) assume_yes=1 ;;
      *)
        echo "unknown argument $1" >&2
        exit 2
        ;;
    esac
    shift
  done
  local record_dir="/var/lib/${PRODUCT}-install"
  local record="${record_dir}/record.env"

  sudo -n true 2>/dev/null || sudo -v
  if sudo test -f "${record}"; then
    # shellcheck source=/dev/null
    . <(sudo cat "${record}")
  else
    echo "no baseline record (${record}): restoring stock defaults where the record would have said" >&2
  fi
  local remove_ctl=0
  removes_ctl "${keep_ctl}" "${remove_ctl_flag}" "${CTL_PREINSTALLED:-0}" && remove_ctl=1

  if [ "${assume_yes}" != 1 ]; then
    printf 'Remove %s%s from this server? [y/N] ' "${PRODUCT}" "$([ "${remove_ctl}" = 1 ] && echo ' and norsk-ctl')"
    local answer
    read -r answer
    [ "${answer}" = y ] || [ "${answer}" = Y ] || exit 1
  fi

  if have_ctl; then
    info "Product ${PRODUCT}"
    for id in $(ctl instance list -o json | jq -r --arg p "${PRODUCT}" '.instances[] | select(.productName == $p) | .id'); do
      ctl instance delete "${id}" --purge
    done
    for t in $(ctl template list -o json |
      jq -r --arg p "${PRODUCT}" '.productTemplates[] | select(.source.productName == $p) | .name'); do
      ctl template remove "${t}"
    done
    if ctl product exists "${PRODUCT}" >/dev/null 2>&1; then ctl product remove "${PRODUCT}"; fi
  fi
  sudo docker rm -f "norsk-product-${PRODUCT}" >/dev/null 2>&1 || true

  local proxy_images=""
  if [ "${remove_ctl}" = 1 ]; then
    if have_ctl; then
      local others
      others="$(ctl product list -o json | jq -r '[.. | objects | select(has("spec")) | .name] | join(" ")')"
      [ -z "${others}" ] || oops "other products are registered (${others}); re-run with --keep-ctl"
    fi

    info "norsk-ctl"
    # The proxy's images are whatever ctl pulled; read them before the
    # containers go.
    proxy_images="$(sudo docker ps -a --filter name=norsk-proxy --format '{{.Image}}' | sort -u)"
    if have_ctl; then ctl shutdown || true; fi
    sudo systemctl disable --now norsk-ctl.service 2>/dev/null || true
    sudo rm -f /etc/systemd/system/norsk-ctl.service
    sudo rm -rf /etc/systemd/system/norsk-ctl.service.d
    sudo systemctl daemon-reload
    sudo docker rm -f norsk-proxy norsk-proxy-oauth2 norsk-moq-relay >/dev/null 2>&1 || true
    sudo docker network rm norsk-net >/dev/null 2>&1 || true

    local working_dir
    working_dir="$(sudo awk '/^defaultWorkingDirectory:/ { print $2 }' /etc/norsk-ctl/config.yaml 2>/dev/null || true)"
    sudo rm -rf /etc/norsk-ctl /var/lib/norsk-ctl /var/log/norsk-ctl /opt/norsk-ctl \
      /usr/local/bin/norsk-ctl /etc/profile.d/norsk-ctl.sh "${working_dir:-/var/norsk-ctl}"
    # TODO: certbot (--cert-source certbot): delete the certificate and the
    # renewal timer the installer set up.

    info "Kernel tuning"
    sudo rm -f /etc/sysctl.d/90-norsk-tuning.conf
    # Stock Ubuntu 24.04 values stand in when there is no record. Applied before
    # `sysctl --system`, so the box's own sysctl.d settings still win.
    restore() { sudo sysctl -q -w "$1=$2" >/dev/null || echo "warning: could not restore $1" >&2; }
    restore net.core.rmem_max "${SYSCTL_net_core_rmem_max:-212992}"
    restore net.core.wmem_max "${SYSCTL_net_core_wmem_max:-212992}"
    restore net.core.rmem_default "${SYSCTL_net_core_rmem_default:-212992}"
    restore net.core.wmem_default "${SYSCTL_net_core_wmem_default:-212992}"
    restore net.core.netdev_max_backlog "${SYSCTL_net_core_netdev_max_backlog:-1000}"
    restore net.ipv4.tcp_rmem "${SYSCTL_net_ipv4_tcp_rmem:-4096 131072 6291456}"
    restore net.ipv4.tcp_wmem "${SYSCTL_net_ipv4_tcp_wmem:-4096 16384 4194304}"
    restore net.ipv4.tcp_congestion_control "${SYSCTL_net_ipv4_tcp_congestion_control:-cubic}"
    sudo sysctl -q --system >/dev/null

    info "Service user"
    # Deleting the norsk group also takes every member out of it. Docker
    # membership the installer granted goes only when the record shows it was
    # not there before.
    if [ -n "${INVOKING_USER:-}" ] && ! grep -qw docker <<<"${USER_GROUPS_BEFORE:-docker}"; then
      sudo gpasswd -d "${INVOKING_USER}" docker >/dev/null || true
    fi
    if id -u norsk >/dev/null 2>&1; then sudo userdel -r norsk 2>/dev/null || true; fi
    if getent group norsk >/dev/null; then sudo groupdel norsk || true; fi
  fi

  info "Images"
  # Ours, the media and Studio images its instances ran, and the proxy's;
  # anything the record shows was here before stays.
  local product_repo="${IMAGE%:*}" id
  for ref in $(sudo docker image ls --format '{{.Repository}}:{{.Tag}}' |
    grep -E "^(${product_repo}|norskvideo/norsk|norskvideo/norsk-studio|norskvideo/norsk-moq-relay):" || true) ${proxy_images}; do
    id="$(sudo docker image inspect -f '{{.Id}}' "${ref}" 2>/dev/null)" || continue
    grep -qw "${id}" <<<"${IMAGES_BEFORE:-}" && continue
    sudo docker image rm "${ref}" >/dev/null || echo "warning: could not remove ${ref}" >&2
  done

  sudo rm -rf "${record_dir}"

  info "Left behind"
  local left=0
  check() {
    if eval "$2"; then
      echo "  $1"
      left=1
    fi
  }
  check "image ${product_repo}" "sudo docker image ls -q '${product_repo}' | grep -q ."
  check "container norsk-product-${PRODUCT}" "sudo docker ps -aq --filter name=norsk-product-${PRODUCT} | grep -q ."
  if [ "${remove_ctl}" = 1 ]; then
    for p in /etc/norsk-ctl /var/lib/norsk-ctl /var/log/norsk-ctl /opt/norsk-ctl /usr/local/bin/norsk-ctl \
      /etc/profile.d/norsk-ctl.sh /etc/sysctl.d/90-norsk-tuning.conf /etc/systemd/system/norsk-ctl.service \
      /etc/systemd/system/norsk-ctl.service.d; do
      check "${p}" "sudo test -e '${p}'"
    done
    check "user norsk" "id -u norsk >/dev/null 2>&1"
    check "group norsk" "getent group norsk >/dev/null"
    check "docker network norsk-net" "sudo docker network inspect norsk-net >/dev/null 2>&1"
    check "norsk containers" "sudo docker ps -a --format '{{.Names}}' | grep -q '^norsk-'"
  fi
  [ "${left}" = 0 ] && echo "  nothing"
  exit "${left}"
}

if [ "${BASH_SOURCE[0]}" = "$0" ]; then main "$@"; fi
