#!/usr/bin/env bash
# Move a Docker Compose project and its named volumes to another host.
# Source host: this machine
# Destination host: 192.168.8.80
# Project directory on both hosts: /home/tas_councils

set -euo pipefail

# ------------------------- CONFIG -------------------------
DEST_HOST="192.168.8.80"
DEST_USER="${USER}"          # change if the username differs on the new server
PROJECT_DIR="/home/tas_councils"
COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml"
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=5"
# ----------------------------------------------------------

say() { printf "\n%s\n" "$*"; }

need() {
  command -v "$1" >/dev/null 2>&1 || { echo "Missing dependency: $1"; exit 1; }
}

# Prefer 'docker compose', fall back to 'docker-compose'
dc() {
  if docker compose version >/dev/null 2>&1; then
    docker compose "$@"
  else
    docker-compose "$@"
  fi
}

# Remote 'docker compose' wrapper
remote_dc() {
  local cmd="$*"
  ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "bash -lc '
    if docker compose version >/dev/null 2>&1; then dcc=\"docker compose\"; else dcc=\"docker-compose\"; fi
    cd \"${PROJECT_DIR}\" && \$dcc ${cmd}
  '"
}

# ----------------------- PRECHECKS ------------------------
need docker
need rsync
need ssh

[[ -d "${PROJECT_DIR}" ]] || { echo "Project dir not found: ${PROJECT_DIR}"; exit 1; }
[[ -f "${COMPOSE_FILE}" ]] || { echo "Compose file not found: ${COMPOSE_FILE}"; exit 1; }

say "Checking SSH access to ${DEST_USER}@${DEST_HOST}..."
ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" 'echo "OK from $(hostname)"' >/dev/null

say "Checking Docker on destination..."
ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" 'docker version >/dev/null 2>&1' \
  || { echo "Docker not available on destination"; exit 1; }

say "Creating project directory on destination..."
ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "mkdir -p '${PROJECT_DIR}'"

# Determine project name
PROJECT_NAME="${PROJECT_NAME:-$(basename "${PROJECT_DIR}")}"
if [[ -f "${PROJECT_DIR}/.env" ]]; then
  # If .env sets COMPOSE_PROJECT_NAME, use it
  ENV_NAME="$(grep -E '^\s*COMPOSE_PROJECT_NAME\s*=' "${PROJECT_DIR}/.env" | tail -n1 | cut -d= -f2- | tr -d '[:space:]' || true)"
  if [[ -n "${ENV_NAME}" ]]; then
    PROJECT_NAME="${ENV_NAME}"
  fi
fi

say "Project name detected: ${PROJECT_NAME}"

# --------------------- STOP SOURCE STACK ------------------
say "Stopping stack on source host..."
dc -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" down

# -------------------- SYNC PROJECT DIR --------------------
say "Syncing project directory to destination..."
rsync -a --delete -e "ssh ${SSH_OPTS}" "${PROJECT_DIR}/" "${DEST_USER}@${DEST_HOST}:${PROJECT_DIR}/"

# -------------------- COPY NAMED VOLUMES ------------------
say "Finding named volumes for the project..."
mapfile -t VOLUMES < <(docker volume ls --format '{{.Name}}' | grep -E "^${PROJECT_NAME}_" || true)

if [[ ${#VOLUMES[@]} -eq 0 ]]; then
  say "No named volumes found with prefix ${PROJECT_NAME}_"
else
  say "Will copy ${#VOLUMES[@]} volume(s):"
  printf '  - %s\n' "${VOLUMES[@]}"

  for VOL in "${VOLUMES[@]}"; do
    say "Copying volume: ${VOL}"
    # Create volume on destination if it does not exist
    ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "docker volume inspect '${VOL}' >/dev/null 2>&1 || docker volume create '${VOL}' >/dev/null"

    # Stream tar from source volume into destination volume
    docker run --rm -v "${VOL}:/src:ro" busybox sh -c "cd /src && tar -cpf - ." \
      | ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "docker run --rm -i -v '${VOL}:/dest' busybox sh -c 'cd /dest && tar -xpf -'"
  done
fi

# ------------------ START DESTINATION STACK ----------------
say "Starting stack on destination host..."
# Pull images first. If the destination has no Internet, comment out the pull line.
ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "bash -lc '
  cd \"${PROJECT_DIR}\"
  if docker compose version >/dev/null 2>&1; then dcc=\"docker compose\"; else dcc=\"docker-compose\"; fi
  \$dcc pull || true
  \$dcc up -d
'"

say "Destination stack status:"
ssh ${SSH_OPTS} "${DEST_USER}@${DEST_HOST}" "bash -lc '
  cd \"${PROJECT_DIR}\"
  if docker compose version >/dev/null 2>&1; then dcc=\"docker compose\"; else dcc=\"docker-compose\"; fi
  \$dcc ps
'"

say "Done. Your Compose project and its named volumes have been moved to ${DEST_HOST}."
say "If you used bind mounts outside ${PROJECT_DIR}, review those paths and copy them as needed."
