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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"

MODE="dry-run"
ONLY=""
NO_PRUNE="false"

usage() {
  cat <<'TXT'
Синхронизация systemd-инстансов воркеров с config/workers.php.

Использование:
  bin/workers-sync-systemd --dry-run
  bin/workers-sync-systemd --apply [--only=task1,task2] [--no-prune]

Опции:
  --dry-run  Показать план без изменений (режим по умолчанию).
  --apply    Применить изменения: install unit template + enable/disable инстансов.
  --only     Синхронизировать только указанные задачи (через запятую).
  --no-prune Не отключать лишние systemd-инстансы.
TXT
}

for arg in "$@"; do
  case "$arg" in
    --dry-run)
      MODE="dry-run"
      ;;
    --apply)
      MODE="apply"
      ;;
    --only=*)
      ONLY="${arg#*=}"
      ;;
    --no-prune)
      NO_PRUNE="true"
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      echo "Неизвестный аргумент: $arg" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [[ "$MODE" == "apply" && "${EUID}" -ne 0 ]]; then
  echo "Режим --apply требует запуск от root (или через sudo)." >&2
  exit 2
fi

PHP_BIN="${PHP_BIN:-$(command -v php)}"
if [[ -z "$PHP_BIN" ]]; then
  echo "Не найден php в PATH" >&2
  exit 2
fi

REPO_WORK_DIR="$ROOT_DIR"
SYSTEMD_WORK_DIR="${SYSTEMD_WORK_DIR:-$REPO_WORK_DIR}"
DEFAULT_WORKER_USER="$(stat -c '%U' "$SYSTEMD_WORK_DIR" 2>/dev/null || echo bitrix)"
DEFAULT_WORKER_GROUP="$(stat -c '%G' "$SYSTEMD_WORK_DIR" 2>/dev/null || echo "$DEFAULT_WORKER_USER")"
SYSTEMD_WORKER_USER="${SYSTEMD_WORKER_USER:-$DEFAULT_WORKER_USER}"
SYSTEMD_WORKER_GROUP="${SYSTEMD_WORKER_GROUP:-$DEFAULT_WORKER_GROUP}"
SYSTEMD_BIN_WORKER="${SYSTEMD_BIN_WORKER:-$REPO_WORK_DIR/bin/worker}"

render_systemd_template() {
  cat <<TXT
[Unit]
Description=Rest1C Worker (%i)
After=network.target

[Service]
Type=simple
User=${SYSTEMD_WORKER_USER}
Group=${SYSTEMD_WORKER_GROUP}
WorkingDirectory=${SYSTEMD_WORK_DIR}
ExecStart=${PHP_BIN} ${SYSTEMD_BIN_WORKER} --task=%i
Restart=always
RestartSec=5
KillMode=control-group
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
TXT
}

LIST_CMD=("$PHP_BIN" "bin/worker" "--list-instances")
if [[ -n "$ONLY" ]]; then
  LIST_CMD+=("--only=$ONLY")
fi

mapfile -t DESIRED_INSTANCES < <("${LIST_CMD[@]}")

if [[ "${#DESIRED_INSTANCES[@]}" -eq 0 ]]; then
  echo "Список инстансов пустой. Проверьте config/workers.php или фильтр --only." >&2
  exit 2
fi

declare -A DESIRED_MAP=()
for instance in "${DESIRED_INSTANCES[@]}"; do
  DESIRED_MAP["$instance"]=1
done

run() {
  if [[ "$MODE" == "dry-run" ]]; then
    echo "[dry-run] $*"
    return 0
  fi
  "$@"
}

SYSTEMD_TEMPLATE_TMP="$(mktemp)"
render_systemd_template >"$SYSTEMD_TEMPLATE_TMP"
run install -m 0644 "$SYSTEMD_TEMPLATE_TMP" /etc/systemd/system/rest1c-worker@.service
rm -f "$SYSTEMD_TEMPLATE_TMP"
run systemctl daemon-reload

for instance in "${DESIRED_INSTANCES[@]}"; do
  unit="rest1c-worker@${instance}.service"
  run systemctl enable --now "$unit"
done

if [[ "$NO_PRUNE" == "true" ]]; then
  echo "Пропускаю prune лишних unit-ов (--no-prune)."
  exit 0
fi

if [[ -n "$ONLY" ]]; then
  echo "Пропускаю prune при --only, чтобы не отключать несвязанные задачи."
  exit 0
fi

mapfile -t CURRENT_UNITS < <(systemctl list-unit-files 'rest1c-worker@*.service' --no-legend 2>/dev/null | awk '{print $1}')

for unit in "${CURRENT_UNITS[@]}"; do
  [[ -z "$unit" ]] && continue
  instance="${unit#rest1c-worker@}"
  instance="${instance%.service}"
  # Пропускаем шаблонный unit rest1c-worker@.service (без инстанса),
  # иначе пустой индекс массива вызывает "bad array subscript" при set -u.
  [[ -z "$instance" ]] && continue
  if [[ -z "${DESIRED_MAP[$instance]:-}" ]]; then
    run systemctl disable --now "$unit"
  fi
done
