#!/usr/bin/env bash
# =============================================================================
# Changemaker Lite V2 — Mirror ALL Images to Gitea Registry
#
# Pulls every Docker image used in docker-compose.prod.yml and re-pushes it
# to the Gitea container registry.  After mirroring, release installs can
# pull the entire platform from a single registry — no Docker Hub, GHCR,
# LSCR, GCR, or other external registries needed.
#
# Usage:
#   ./scripts/mirror-images.sh [OPTIONS]
#
# Options:
#   --core-only   Mirror only the essential infrastructure images (postgres,
#                 redis, alpine) — skip platform and communication services
#   --dry-run     Print commands without executing
#   --registry    Override registry (default: gitea.bnkops.com/admin)
#   --help        Show this help
#
# Prerequisites:
#   docker login gitea.bnkops.com
# =============================================================================
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"

# --- Defaults ---
REGISTRY="${GITEA_REGISTRY:-gitea.bnkops.com/admin}"
CORE_ONLY=false
DRY_RUN=false

# --- Colors ---
if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then
  RED='\033[0;31m'  GREEN='\033[0;32m'  YELLOW='\033[0;33m'
  BLUE='\033[0;34m' CYAN='\033[0;36m'   BOLD='\033[1m'  NC='\033[0m'
else
  RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' NC=''
fi

info()    { echo -e "${BLUE}[INFO]${NC}  $*"; }
success() { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC}  $*"; }
error()   { echo -e "${RED}[ERROR]${NC} $*" >&2; }
run()     { if [[ "$DRY_RUN" == "true" ]]; then echo -e "${CYAN}[DRY-RUN]${NC} $*"; else "$@"; fi; }

# --- Arg parser ---
while [[ $# -gt 0 ]]; do
  case "$1" in
    --core-only)  CORE_ONLY=true; shift ;;
    --dry-run)    DRY_RUN=true; shift ;;
    --registry)   REGISTRY="$2"; shift 2 ;;
    --help|-h)
      sed -n '2,30p' "$0" | grep '^#' | sed 's/^# \?//'
      exit 0 ;;
    # Legacy flag — now default behavior
    --all)        shift ;;
    *) error "Unknown option: $1"; exit 1 ;;
  esac
done

# =============================================================================
# IMAGE MAP — source → destination name in Gitea registry
#
# Naming conventions:
#   - Simple names kept as-is: postgres, redis, alpine, mongo, mysql, nats
#   - Namespaced → short name: nocodb/nocodb → nocodb, listmonk/listmonk → listmonk
#   - Conflicts resolved explicitly:
#       gotify/server   → gotify      (not "server")
#       vaultwarden/server → vaultwarden (not "server")
#       jitsi/web       → jitsi-web   (not "web")
#       lscr.io/.../nginx → ls-nginx  (not "nginx", avoids changemaker-nginx conflict)
#       alpine/curl     → alpine-curl (not "curl")
#   - Untagged images get :latest appended
# =============================================================================

# --- Core infrastructure (always mirrored) ---
declare -A CORE_IMAGES=(
  # PostgreSQL
  ["postgres:16-alpine"]="postgres:16-alpine"
  ["postgres:17-alpine"]="postgres:17-alpine"
  # Redis
  ["redis:7-alpine"]="redis:7-alpine"
  # Alpine (init containers)
  ["alpine:3"]="alpine:3"
  ["alpine/curl:8.11.1"]="alpine-curl:8.11.1"
)

# --- Platform services ---
declare -A PLATFORM_IMAGES=(
  # NocoDB
  ["nocodb/nocodb:0.301.3"]="nocodb:0.301.3"
  # Listmonk
  ["listmonk/listmonk:v6.0.0"]="listmonk:v6.0.0"
  # MailHog
  ["mailhog/mailhog:v1.0.1"]="mailhog:v1.0.1"
  # MkDocs
  ["squidfunk/mkdocs-material:latest"]="mkdocs-material:latest"
  # MkDocs static site server (LinuxServer nginx — NOT our custom nginx)
  ["lscr.io/linuxserver/nginx:1.28.2"]="ls-nginx:1.28.2"
  # n8n workflow automation
  ["docker.n8n.io/n8nio/n8n:latest"]="n8n:latest"
  # Homepage dashboard
  ["ghcr.io/gethomepage/homepage:v0.7.2"]="homepage:v0.7.2"
  # Gitea + MySQL
  ["gitea/gitea:1.23.7"]="gitea:1.23.7"
  ["mysql:8"]="mysql:8"
  # Mini QR
  ["ghcr.io/lyqht/mini-qr:v0.26.0"]="mini-qr:v0.26.0"
  # Excalidraw
  ["excalidraw/excalidraw:latest"]="excalidraw:latest"
  # Vaultwarden
  ["vaultwarden/server:1.35.4"]="vaultwarden:1.35.4"
  # Docker socket proxy
  ["tecnativa/docker-socket-proxy:v0.4.2"]="docker-socket-proxy:v0.4.2"
  # Pangolin tunnel
  ["fosrl/newt:latest"]="newt:latest"
  # Plain nginx (CCP instances: reverse proxy + mkdocs-site-server)
  ["nginx:alpine"]="nginx:alpine"
  # Code Server (LinuxServer)
  ["lscr.io/linuxserver/code-server:latest"]="code-server:latest"
)

# --- Communication services (Rocket.Chat, Gancio, Jitsi) ---
declare -A COMMS_IMAGES=(
  # Rocket.Chat + dependencies
  ["rocketchat/rocket.chat:7.9.7"]="rocketchat:7.9.7"
  ["mongo:6.0"]="mongo:6.0"
  ["nats:2.11-alpine"]="nats:2.11-alpine"
  # Gancio events
  ["cisti/gancio:1.28.2"]="gancio:1.28.2"
  # Jitsi Meet (4 containers)
  ["jitsi/web:stable-9823"]="jitsi-web:stable-9823"
  ["jitsi/prosody:stable-9823"]="jitsi-prosody:stable-9823"
  ["jitsi/jicofo:stable-9823"]="jitsi-jicofo:stable-9823"
  ["jitsi/jvb:stable-9823"]="jitsi-jvb:stable-9823"
)

# --- Monitoring stack ---
declare -A MONITORING_IMAGES=(
  ["prom/prometheus:v3.10.0"]="prometheus:v3.10.0"
  ["grafana/grafana:12.3.0"]="grafana:12.3.0"
  ["prom/alertmanager:v0.31.1"]="alertmanager:v0.31.1"
  ["oliver006/redis_exporter:v1.81.0"]="redis_exporter:v1.81.0"
  ["gcr.io/cadvisor/cadvisor:v0.55.1"]="cadvisor:v0.55.1"
  ["prom/node-exporter:v1.10.2"]="node-exporter:v1.10.2"
  ["gotify/server:2.9.0"]="gotify:v2.9.0"
)

# =============================================================================

mirror_image() {
  local source="$1"
  local dest_name="$2"
  local dest="${REGISTRY}/${dest_name}"

  info "Mirroring ${source} → ${dest}..."
  run docker pull "${source}"
  run docker tag "${source}" "${dest}"
  run docker push "${dest}"
  success "Mirrored ${dest_name}"
}

mirror_map() {
  local -n map=$1
  local label="$2"
  echo ""
  echo -e "${BOLD}── ${label} (${#map[@]} images) ──${NC}"
  for source in "${!map[@]}"; do
    if ! mirror_image "$source" "${map[$source]}"; then
      FAILED+=("$source")
      warn "Failed to mirror: $source (continuing...)"
    else
      ((MIRRORED++)) || true
    fi
  done
}

echo -e "${BOLD}Changemaker Lite — Mirror ALL Images to Gitea${NC}"
echo "  Registry:  $REGISTRY"
echo "  Core only: $CORE_ONLY"
echo ""

FAILED=()
MIRRORED=0
TOTAL=0

# Always mirror core
for _ in "${!CORE_IMAGES[@]}"; do ((TOTAL++)) || true; done
mirror_map CORE_IMAGES "Core Infrastructure"

if [[ "$CORE_ONLY" != "true" ]]; then
  for _ in "${!PLATFORM_IMAGES[@]}"; do ((TOTAL++)) || true; done
  for _ in "${!COMMS_IMAGES[@]}"; do ((TOTAL++)) || true; done
  for _ in "${!MONITORING_IMAGES[@]}"; do ((TOTAL++)) || true; done

  mirror_map PLATFORM_IMAGES "Platform Services"
  mirror_map COMMS_IMAGES "Communication Services"
  mirror_map MONITORING_IMAGES "Monitoring Stack"
else
  warn "Skipping platform, communication, and monitoring images (--core-only)"
fi

echo ""
echo -e "${BOLD}── Summary ──${NC}"
if [[ ${#FAILED[@]} -eq 0 ]]; then
  success "All ${MIRRORED} images mirrored to ${REGISTRY}"
else
  warn "Mirrored ${MIRRORED}/${TOTAL} images"
  error "Failed: ${FAILED[*]}"
  exit 1
fi
