#!/usr/bin/env bash
# Деплой GooSeek в Kubernetes (локальный K3s на этой машине)
# Docker build → kubectl apply → rollout restart (подхват новых образов)
# Конфигурация: deploy/k3s/deploy.config.yaml
#
# Использование:
#   ./deploy/k3s/deploy.sh              # полный деплой (build + apply)
#   ./deploy/k3s/deploy.sh --no-build   # только apply манифестов
#   ./deploy/k3s/deploy.sh --build-only # только сборка образов
#   ./deploy/k3s/deploy.sh --list       # показать включённые сервисы
#   ./deploy/k3s/deploy.sh --skip-migrate  # без миграции auth-svc (быстрее)
#   ./deploy/k3s/deploy.sh --migrate    # принудительно запустить миграцию auth-svc

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONFIG="$SCRIPT_DIR/deploy.config.yaml"

# Контекст сборки: . = корень репо, иначе путь к папке сервиса
get_build_ctx() {
  case "$1" in
    web-svc|auth-svc) echo "." ;;
    profile-svc) echo "services/profile-svc" ;;
    api-gateway) echo "services/api-gateway" ;;
    chat-svc) echo "services/chat-svc" ;;
    search-svc) echo "services/search-svc" ;;
    discover-svc) echo "services/discover-svc" ;;
    finance-svc) echo "services/finance-svc" ;;
    travel-svc) echo "services/travel-svc" ;;
    memory-svc) echo "services/memory-svc" ;;
    library-svc) echo "services/library-svc" ;;
    create-svc) echo "services/create-svc" ;;
    projects-svc) echo "services/projects-svc" ;;
    notifications-svc) echo "services/notifications-svc" ;;
    billing-svc) echo "services/billing-svc" ;;
    audit-svc) echo "services/audit-svc" ;;
    cache-worker) echo "services/cache-worker" ;;
    llm-svc) echo "services/llm-svc" ;;
    children-svc|medicine-svc|education-svc|goods-svc|health-svc|psychology-svc|sports-svc|realestate-svc|shopping-svc|games-svc|taxes-svc|legislation-svc) echo "" ;;
    *) echo "" ;;
  esac
}

# Манифест для сервиса
get_manifest() {
  case "$1" in
    web-svc) echo "web-svc.yaml" ;;
    api-gateway) echo "api-gateway.yaml" ;;
    auth-svc) echo "auth-svc.yaml" ;;
    profile-svc) echo "profile-svc.yaml" ;;
    chat-svc) echo "chat-svc.yaml" ;;
    search-svc) echo "search-svc.yaml" ;;
    discover-svc) echo "discover-svc.yaml" ;;
    finance-svc) echo "finance-svc.yaml" ;;
    travel-svc) echo "travel-svc.yaml" ;;
    memory-svc) echo "memory-svc.yaml" ;;
    library-svc) echo "library-svc.yaml" ;;
    create-svc) echo "create-svc.yaml" ;;
    projects-svc) echo "projects-svc.yaml" ;;
    notifications-svc) echo "notifications-svc.yaml" ;;
    billing-svc) echo "billing-svc.yaml" ;;
    audit-svc) echo "audit-svc.yaml" ;;
    cache-worker) echo "cache-worker.yaml" ;;
    llm-svc) echo "llm-svc.yaml" ;;
    children-svc|medicine-svc|education-svc|goods-svc|health-svc|psychology-svc|sports-svc|realestate-svc|shopping-svc|games-svc|taxes-svc|legislation-svc) echo "" ;;
    *) echo "" ;;
  esac
}

get_enabled_services() {
  local in_services=0
  while IFS= read -r line; do
    if [[ "$line" =~ ^[a-z].*: ]]; then
      [[ "$line" =~ ^ingress: ]] && in_services=0
    fi
    if [[ "$line" =~ ^services: ]]; then
      in_services=1
      continue
    fi
    if (( in_services )) && [[ "$line" =~ ^[[:space:]]+([a-z0-9-]+):[[:space:]]+true ]]; then
      echo "${BASH_REMATCH[1]}"
    fi
  done < "$CONFIG"
}

get_ingress_enabled() {
  grep -A 5 "^ingress:" "$CONFIG" 2>/dev/null | grep "enabled:" | grep -q "true"
}

get_ssl_auto() {
  grep -A 25 "^ingress:" "$CONFIG" 2>/dev/null | grep -E "^\s+auto:" | head -1 | sed 's/.*auto:[[:space:]]*//' | sed 's/[[:space:]#].*//' | tr -d ' '
}

# SSL: cert-manager + Let's Encrypt (production https://gooseek.ru)
do_ssl_production() {
  if ! kubectl get deployment -n ingress-nginx ingress-nginx-controller &>/dev/null 2>&1; then
    echo "  ⚠ ingress-nginx не найден. Установите: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml"
    return 1
  fi
  local cert_manager_version="v1.13.0"
  if ! kubectl get deployment -n cert-manager cert-manager &>/dev/null 2>&1; then
    echo "  → cert-manager"
    kubectl apply -f "https://github.com/cert-manager/cert-manager/releases/download/${cert_manager_version}/cert-manager.yaml"
    echo "  Ожидание cert-manager (до 2 мин)..."
    kubectl wait --for=condition=Available deployment/cert-manager -n cert-manager --timeout=120s 2>/dev/null || true
    kubectl wait --for=condition=Available deployment/cert-manager-webhook -n cert-manager --timeout=120s 2>/dev/null || true
  else
    echo "  cert-manager уже установлен"
  fi
  echo "  → ClusterIssuer letsencrypt-prod"
  kubectl apply -f "$SCRIPT_DIR/ssl/cert-manager-issuer.yaml"
  echo "  → Ingress (TLS, gooseek.ru)"
  kubectl delete ingress gooseek-web-ingress -n gooseek 2>/dev/null || true
  kubectl apply -f "$SCRIPT_DIR/ingress-production.yaml"
}

build_image() {
  local svc="$1"
  local ctx
  ctx=$(get_build_ctx "$svc")
  [[ -z "$ctx" ]] && return 1
  local img="gooseek/${svc}:latest"
  local df="services/${svc}/Dockerfile"

  echo "  → $img"
  if [[ "$ctx" == "." ]]; then
    docker build -t "$img" -f "$df" .
  else
    docker build -t "$img" -f "$df" "$ctx"
  fi
}

do_build() {
  local enabled
  enabled=($(get_enabled_services))
  if [[ ${#enabled[@]} -eq 0 ]]; then
    echo "Ошибка: нет включённых сервисов в $CONFIG"
    exit 1
  fi

  echo "=== Сборка образов (${#enabled[@]} сервисов) ==="
  cd "$REPO_ROOT"
  for svc in "${enabled[@]}"; do
    if get_build_ctx "$svc" | grep -q .; then
      build_image "$svc"
    else
      echo "  ⚠ Пропуск $svc (нет конфига сборки)"
    fi
  done
}

do_apply() {
  local enabled
  enabled=($(get_enabled_services))
  if [[ ${#enabled[@]} -eq 0 ]]; then
    echo "Ошибка: нет включённых сервисов в $CONFIG"
    exit 1
  fi

  echo "=== Namespace ==="
  kubectl apply -f "$SCRIPT_DIR/namespace.yaml"

  echo ""
  echo "=== Config (production https://gooseek.ru) ==="
  local auth_url="https://gooseek.ru"
  local origins="https://gooseek.ru,https://www.gooseek.ru"
  kubectl create configmap gooseek-env -n gooseek \
    --from-literal=allowed-origins="$origins" \
    --dry-run=client -o yaml | kubectl apply -f -
  kubectl create configmap gooseek-env -n gooseek-auth \
    --from-literal=better-auth-url="$auth_url" \
    --from-literal=trusted-origins="$origins" \
    --dry-run=client -o yaml | kubectl apply -f -

  echo ""
  echo "=== Манифесты (${#enabled[@]} сервисов) ==="
  for svc in "${enabled[@]}"; do
    local mf
    mf=$(get_manifest "$svc")
    if [[ -n "$mf" && -f "$SCRIPT_DIR/$mf" ]]; then
      echo "  → $mf"
      kubectl apply -f "$SCRIPT_DIR/$mf"
    else
      echo "  ⚠ Пропуск $svc (манифест не найден)"
    fi
  done

  echo ""
  echo "=== Rollout restart (подхват новых образов :latest) ==="
  for svc in "${enabled[@]}"; do
    local mf
    mf=$(get_manifest "$svc")
    [[ -z "$mf" || ! -f "$SCRIPT_DIR/$mf" ]] && continue
    case "$svc" in
      auth-svc)
        kubectl rollout restart deployment/auth-svc -n gooseek-auth 2>/dev/null || true
        echo "  → auth-svc (gooseek-auth)"
        ;;
      cache-worker)
        echo "  (cache-worker — CronJob, пропуск)"
        ;;
      *)
        kubectl rollout restart deployment/"$svc" -n gooseek 2>/dev/null || true
        echo "  → $svc"
        ;;
    esac
  done

  # Миграция auth-svc — только при --migrate (не при каждом деплое)
  # Запускайте ./deploy.sh --migrate после обновления auth-svc или при первой установке
  # PVC ReadWriteOnce: временно scale down auth-svc, чтобы migrate pod мог смонтировать том
  if [[ "$FORCE_MIGRATE" -eq 1 ]] && printf '%s\n' "${enabled[@]}" | grep -qx "auth-svc"; then
    echo ""
    echo "=== Миграция auth-svc ==="
    kubectl scale deployment auth-svc -n gooseek-auth --replicas=0 2>/dev/null || true
    echo "  Ожидание остановки auth-svc..."
    kubectl wait --for=delete pod -l app=auth-svc -n gooseek-auth --timeout=60s 2>/dev/null || sleep 8
    kubectl run auth-migrate --rm --restart=Never \
      --image=gooseek/auth-svc:latest \
      --namespace=gooseek-auth \
      --overrides='{"spec":{"containers":[{"name":"migrate","image":"gooseek/auth-svc:latest","command":["npx","@better-auth/cli","migrate","--yes"],"env":[{"name":"DATABASE_PATH","value":"/data/auth.db"}],"volumeMounts":[{"name":"auth-data","mountPath":"/data"}]}],"volumes":[{"name":"auth-data","persistentVolumeClaim":{"claimName":"auth-data-pvc"}}]}}' \
      2>/dev/null || echo "  ⚠ Миграция завершилась с ошибкой"
    kubectl scale deployment auth-svc -n gooseek-auth --replicas=1 2>/dev/null || true
    echo "  auth-svc возвращён в работу"
  fi

  # Ingress — production https://gooseek.ru
  if get_ingress_enabled; then
    echo ""
    echo "=== Ingress (https://gooseek.ru) ==="
    kubectl delete ingress gooseek-web-ingress -n gooseek 2>/dev/null || true
    if [[ -f "$SCRIPT_DIR/ssl/backup/fullchain.pem" ]] && [[ -f "$SCRIPT_DIR/ssl/backup/privkey.pem" ]]; then
      echo "  SSL: серты из backup/"
      "$SCRIPT_DIR/ssl/apply-secret.sh" 2>/dev/null || true
      kubectl apply -f "$SCRIPT_DIR/ingress-production-manual.yaml"
    else
      local ssl_auto
      ssl_auto=$(get_ssl_auto)
      ssl_auto=${ssl_auto:-true}
      if [[ "$ssl_auto" == "true" ]]; then
        echo "  SSL: cert-manager (Let's Encrypt, первый деплой)"
        do_ssl_production
      else
        echo "  ⚠ Нет сертов в backup/. Варианты:"
        echo "    1) ssl.auto: true в deploy.config.yaml — cert-manager получит серты"
        echo "    2) Получите серты (certbot), положите в deploy/k3s/ssl/backup/, затем перезапустите деплой"
        exit 1
      fi
    fi
  fi

  echo ""
  echo "=== Готово ==="
  echo "Проверка: kubectl get pods -n gooseek"
}

do_list() {
  echo "Включённые сервисы:"
  get_enabled_services | while read -r svc; do
    echo "  - $svc"
  done
  echo ""
  echo "Ingress: $(get_ingress_enabled && echo 'enabled' || echo 'disabled')"
  echo "Production: https://gooseek.ru"
  if [[ -f "$SCRIPT_DIR/ssl/backup/fullchain.pem" ]] && [[ -f "$SCRIPT_DIR/ssl/backup/privkey.pem" ]]; then
    echo "SSL: backup/"
  else
    if [[ "$(get_ssl_auto)" == "true" ]]; then
      echo "SSL: cert-manager (Let's Encrypt)"
    else
      echo "SSL: нужен backup/ или ssl.auto: true"
    fi
  fi
}

# Main
NO_BUILD=0
BUILD_ONLY=0
LIST_ONLY=0
FORCE_MIGRATE=0

for arg in "$@"; do
  case "$arg" in
    --no-build)     NO_BUILD=1 ;;
    --build-only)   BUILD_ONLY=1 ;;
    --list)         LIST_ONLY=1 ;;
    --migrate)      FORCE_MIGRATE=1 ;;
    --skip-migrate) FORCE_MIGRATE=0 ;;
    -h|--help)
      echo "Использование: $0 [--no-build|--build-only|--list|--migrate|--skip-migrate]"
      echo ""
      echo "  --no-build     Только apply манифестов (без сборки образов)"
      echo "  --build-only   Только сборка образов (без apply)"
      echo "  --list         Показать включённые сервисы из deploy.config.yaml"
      echo "  --migrate      Запустить миграцию auth-svc (при изменении схемы)"
      echo "  --skip-migrate Пропустить миграцию (по умолчанию)"
      exit 0
      ;;
  esac
done

if [[ "$LIST_ONLY" -eq 1 ]]; then
  do_list
  exit 0
fi

if [[ "$BUILD_ONLY" -eq 1 ]]; then
  do_build
  exit 0
fi

if [[ "$NO_BUILD" -eq 0 ]]; then
  do_build
  echo ""
fi

do_apply
