#!/usr/bin/env bash
#
# Обновление уже установленного prod-стека (каталог INSTALL_DIR).
#
# Скачивает актуальные compose/конфиги, при необходимости правит публичные
# URL в .env (секреты не трогает) и пересоздаёт контейнеры.
#
# Запуск из каталога установки:
#   cd /opt/unishift
#   ./update.sh
#   PUBLIC_HOST=203.0.113.10 ./update.sh
#   PUBLIC_HOST=app.example.com PUBLIC_SCHEME=https ./update.sh
#
# Первая установка — install.sh (curl | bash). Этот скрипт туда кладёт
# update.sh; на старых инсталляциях скачайте его один раз:
#   curl -fsSL -o /opt/unishift/update.sh \
#     https://storage.unishift.ru/services/prod/update.sh
#   chmod +x /opt/unishift/update.sh
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="${INSTALL_DIR:-$SCRIPT_DIR}"
BASE_URL="${BASE_URL:-https://storage.unishift.ru/services/prod}"

PUBLIC_HOST="${PUBLIC_HOST:-}"
PUBLIC_SCHEME="${PUBLIC_SCHEME:-http}"

FILES=(
  docker-compose.yaml
  migrate.sh
  postgres/init/00-enable-pgvector.sql
  postgres/init/01-create-databases.sql
  centrifugo/config.json
  searxng/settings.yml
)

log()  { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m warn:\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[1;31mОшибка:\033[0m %s\n' "$*" >&2; exit 1; }

env_get() {
  local line
  line=$(grep -E "^${1}=" .env 2>/dev/null | tail -1 || true)
  printf '%s' "${line#*=}"
}

upsert_env() {
  local key="$1" val="$2"
  local escaped
  escaped=$(printf '%s' "$val" | sed 's/[|&]/\\&/g')
  if grep -q "^${key}=" .env; then
    sed -i "s|^${key}=.*|${key}=${escaped}|" .env
  else
    printf '%s=%s\n' "$key" "$val" >> .env
  fi
}

for cmd in docker curl; do
  command -v "$cmd" >/dev/null 2>&1 || die "нужна утилита '$cmd'"
done
docker compose version >/dev/null 2>&1 || die "нужен docker compose v2"
[ -f "$INSTALL_DIR/.env" ] || die "нет $INSTALL_DIR/.env — сначала install.sh"

cd "$INSTALL_DIR"

log "Обновляю файлы в $INSTALL_DIR из $BASE_URL"
old_umask=$(umask)
umask 022
for rel in "${FILES[@]}"; do
  log "Скачиваю $rel"
  curl -fsSL --create-dirs -o "$INSTALL_DIR/$rel" "$BASE_URL/$rel" \
    || die "не удалось скачать $BASE_URL/$rel"
  [ -s "$INSTALL_DIR/$rel" ] || die "скачанный файл пуст: $rel"
done
umask "$old_umask"
chmod +x "$INSTALL_DIR/migrate.sh"
chmod -R a+rX \
  "$INSTALL_DIR/postgres" \
  "$INSTALL_DIR/centrifugo" \
  "$INSTALL_DIR/searxng"

if [ -n "$PUBLIC_HOST" ]; then
  CLIENT_PORT="${CLIENT_PORT:-$(env_get CLIENT_PORT)}"
  CENTRIFUGO_PORT="${CENTRIFUGO_PORT:-$(env_get CENTRIFUGO_PORT)}"
  CLIENT_PORT="${CLIENT_PORT:-18080}"
  CENTRIFUGO_PORT="${CENTRIFUGO_PORT:-18100}"

  case "$PUBLIC_SCHEME" in
    http)
      WEB_BASE_URL="${WEB_BASE_URL:-${PUBLIC_SCHEME}://${PUBLIC_HOST}:${CLIENT_PORT}}"
      CENTRIFUGO_WS_URL="${CENTRIFUGO_WS_URL:-ws://${PUBLIC_HOST}:${CENTRIFUGO_PORT}/connection/websocket}"
      CENTRIFUGO_ALLOWED_ORIGINS="${CENTRIFUGO_ALLOWED_ORIGINS:-${PUBLIC_SCHEME}://${PUBLIC_HOST}:${CLIENT_PORT}}"
      SESSION_SECURE="${SESSION_SECURE:-false}"
      ;;
    https)
      WEB_BASE_URL="${WEB_BASE_URL:-${PUBLIC_SCHEME}://${PUBLIC_HOST}}"
      CENTRIFUGO_WS_URL="${CENTRIFUGO_WS_URL:-wss://${PUBLIC_HOST}/connection/websocket}"
      CENTRIFUGO_ALLOWED_ORIGINS="${CENTRIFUGO_ALLOWED_ORIGINS:-${PUBLIC_SCHEME}://${PUBLIC_HOST}}"
      SESSION_SECURE="${SESSION_SECURE:-true}"
      ;;
    *) die "PUBLIC_SCHEME должен быть http или https, получено: $PUBLIC_SCHEME" ;;
  esac

  log "Пишу публичные URL в .env (PUBLIC_HOST=$PUBLIC_HOST)"
  upsert_env WEB_BASE_URL "$WEB_BASE_URL"
  upsert_env CENTRIFUGO_WS_URL "$CENTRIFUGO_WS_URL"
  upsert_env CENTRIFUGO_ALLOWED_ORIGINS "$CENTRIFUGO_ALLOWED_ORIGINS"
  upsert_env SESSION_SECURE "$SESSION_SECURE"
else
  WEB_BASE_URL="$(env_get WEB_BASE_URL)"
  CENTRIFUGO_WS_URL="$(env_get CENTRIFUGO_WS_URL)"
fi

# Себя — в конце, через временный файл: bash читает скрипт по ходу выполнения.
log "Скачиваю update.sh"
tmp=$(mktemp)
curl -fsSL -o "$tmp" "$BASE_URL/update.sh" || die "не удалось скачать update.sh"
chmod +x "$tmp"
mv "$tmp" "$INSTALL_DIR/update.sh"

log "Накатываю миграции"
./migrate.sh </dev/null

log "Поднимаю стек"
docker compose up -d

echo
log "Готово"
echo "  UI:         ${WEB_BASE_URL:-$(env_get WEB_BASE_URL)}"
echo "  WebSocket:  ${CENTRIFUGO_WS_URL:-$(env_get CENTRIFUGO_WS_URL)}"
echo
docker compose ps
