#!/usr/bin/env bash
set -euo pipefail

APP_NAME="cmdb-backend"
DEPLOY_HOST="${CMDB_DEPLOY_HOST:-root@cmdb}"
APP_DIR="${CMDB_APP_DIR:-/apps}"
LOCAL_BIN="${CMDB_LOCAL_BIN:-dist/cmdb-backend-linux-amd64}"
SUPERVISOR_CONF_LOCAL="${CMDB_SUPERVISOR_CONF:-deploy/supervisor/cmdb-backend.conf}"
REMOTE_TMP_BIN="/tmp/${APP_NAME}.$$"
REMOTE_TMP_CONF="/tmp/${APP_NAME}.conf.$$"
INSTALL_SUPERVISOR=0

usage() {
  cat <<USAGE
Usage: $0 [--install-supervisor]

Builds a linux/amd64 cmdb binary locally, uploads it to ${DEPLOY_HOST},
and lets supervisor manage the process instead of nohup.

Environment overrides:
  CMDB_DEPLOY_HOST       SSH target, default: root@cmdb
  CMDB_APP_DIR           Remote app dir, default: /apps
  CMDB_LOCAL_BIN         Local build output, default: dist/cmdb-backend-linux-amd64
  CMDB_SUPERVISOR_CONF   Local supervisor conf, default: deploy/supervisor/cmdb-backend.conf

Options:
  --install-supervisor   Install supervisor with apt-get if missing on the remote Ubuntu host.
USAGE
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --install-supervisor)
      INSTALL_SUPERVISOR=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [[ ! -f "main.go" || ! -f "go.mod" ]]; then
  echo "must run from the cmdb-backend repository root" >&2
  exit 1
fi
if [[ ! -f "${SUPERVISOR_CONF_LOCAL}" ]]; then
  echo "supervisor config not found: ${SUPERVISOR_CONF_LOCAL}" >&2
  exit 1
fi

mkdir -p "$(dirname "${LOCAL_BIN}")"
echo "== build ${LOCAL_BIN} =="
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "${LOCAL_BIN}" ./main.go

echo "== upload binary and supervisor config to ${DEPLOY_HOST} =="
scp "${LOCAL_BIN}" "${DEPLOY_HOST}:${REMOTE_TMP_BIN}"
scp "${SUPERVISOR_CONF_LOCAL}" "${DEPLOY_HOST}:${REMOTE_TMP_CONF}"

echo "== install and restart via supervisor on ${DEPLOY_HOST} =="
ssh "${DEPLOY_HOST}" "APP_NAME='${APP_NAME}' APP_DIR='${APP_DIR}' REMOTE_TMP_BIN='${REMOTE_TMP_BIN}' REMOTE_TMP_CONF='${REMOTE_TMP_CONF}' INSTALL_SUPERVISOR='${INSTALL_SUPERVISOR}' bash -s" <<'REMOTE'
set -euo pipefail

if ! command -v supervisorctl >/dev/null 2>&1; then
  if [[ "${INSTALL_SUPERVISOR}" != "1" ]]; then
    echo "supervisorctl not found. Re-run with --install-supervisor to install supervisor." >&2
    exit 1
  fi
  apt-get update
  apt-get install -y supervisor
fi

systemctl enable --now supervisor >/dev/null 2>&1 || systemctl enable --now supervisord >/dev/null 2>&1 || true
install -d "${APP_DIR}" "${APP_DIR}/backup"
install -m 0755 "${REMOTE_TMP_BIN}" "${APP_DIR}/${APP_NAME}.new"
install -m 0644 "${REMOTE_TMP_CONF}" "/etc/supervisor/conf.d/${APP_NAME}.conf"

program_known=0
if supervisorctl status "${APP_NAME}" >/dev/null 2>&1; then
  program_known=1
  supervisorctl stop "${APP_NAME}" >/dev/null 2>&1 || true
fi

# First adoption from nohup: terminate the unmanaged process before supervisor starts it.
if pgrep -x "${APP_NAME}" >/dev/null 2>&1; then
  pkill -TERM -x "${APP_NAME}" || true
  for _ in $(seq 1 10); do
    pgrep -x "${APP_NAME}" >/dev/null 2>&1 || break
    sleep 1
  done
  if pgrep -x "${APP_NAME}" >/dev/null 2>&1; then
    pkill -KILL -x "${APP_NAME}" || true
  fi
fi

if [[ -x "${APP_DIR}/${APP_NAME}" ]]; then
  cp "${APP_DIR}/${APP_NAME}" "${APP_DIR}/backup/${APP_NAME}.bak.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true
fi
mv "${APP_DIR}/${APP_NAME}.new" "${APP_DIR}/${APP_NAME}"
chmod +x "${APP_DIR}/${APP_NAME}"
rm -f "${REMOTE_TMP_BIN}" "${REMOTE_TMP_CONF}"

supervisorctl reread
supervisorctl update

if [[ "${program_known}" == "1" ]]; then
  supervisorctl restart "${APP_NAME}" || supervisorctl start "${APP_NAME}"
elif supervisorctl status "${APP_NAME}" | grep -q RUNNING; then
  :
else
  supervisorctl start "${APP_NAME}" || supervisorctl restart "${APP_NAME}"
fi
sleep 3
supervisorctl status "${APP_NAME}"
curl -fsS --max-time 5 http://127.0.0.1:8080/check_health
printf '\n'
REMOTE
