FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        openssh-client \
        openssl \
        curl \
        sshfs \
        restic \
        fuse3 \
        sshpass && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY id_ed25519.enc /app/id_ed25519.enc

RUN cat > /app/run.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail

# ══════════════════════════════════════════════════════════════════════════════
# VALIDATION
# ══════════════════════════════════════════════════════════════════════════════
REQUIRED_VARS=(KEY_PASSWORD REMOTE_HOST RESTIC_PASSWORD SSH_PASSWORD)
for var in "${REQUIRED_VARS[@]}"; do
  if [[ -z "${!var:-}" ]]; then
    echo "❌ Error: Missing required variable: $var"
    exit 1
  fi
done

MODE="${MODE:-BACKUP}"
MOUNT_REMOTE="${MOUNT_REMOTE:-root@n.h-y.st:/mnt/data}"
MOUNT_POINT="/mnt/data"
RESTIC_REPO="$MOUNT_POINT/restic-repo"
COMPOSE_DIR="${COMPOSE_DIR:-/root/docker}"

echo "
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  🚀 Backup/Restore Tool
  Mode       : $MODE
  Target     : root@$REMOTE_HOST
  Compose    : $COMPOSE_DIR
  Mount      : $MOUNT_REMOTE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"

# ══════════════════════════════════════════════════════════════════════════════
# CLEANUP TRAP
# ══════════════════════════════════════════════════════════════════════════════
cleanup() {
  echo "🧹 Cleaning up local secrets..."
  rm -f ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub
}
trap cleanup EXIT

# ══════════════════════════════════════════════════════════════════════════════
# DECRYPT SSH KEY
# ══════════════════════════════════════════════════════════════════════════════
echo "🔑 Decrypting SSH key..."
mkdir -p ~/.ssh && chmod 700 ~/.ssh

if ! openssl enc -d -aes-256-cbc -pbkdf2 \
    -in /app/id_ed25519.enc \
    -out ~/.ssh/id_ed25519 \
    -pass pass:"$KEY_PASSWORD" 2>/dev/null; then
  echo "❌ Failed to decrypt SSH key — check KEY_PASSWORD"
  exit 1
fi
chmod 600 ~/.ssh/id_ed25519
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub 2>/dev/null || true

# ══════════════════════════════════════════════════════════════════════════════
# SSH HELPERS
# ══════════════════════════════════════════════════════════════════════════════
KEY_SSH() {
  ssh \
    -o StrictHostKeyChecking=no \
    -o ConnectTimeout=10 \
    -o BatchMode=yes \
    -o ServerAliveInterval=15 \
    -o ServerAliveCountMax=3 \
    -i ~/.ssh/id_ed25519 \
    "$@"
}

PASS_SSH() {
  sshpass -p "$SSH_PASSWORD" ssh \
    -o StrictHostKeyChecking=no \
    -o ConnectTimeout=10 \
    -o ServerAliveInterval=15 \
    -o ServerAliveCountMax=3 \
    "$@"
}

# ══════════════════════════════════════════════════════════════════════════════
# CONNECTIVITY + AUTH BOOTSTRAP
# ══════════════════════════════════════════════════════════════════════════════
echo "🔍 Testing connectivity to $REMOTE_HOST..."

if KEY_SSH "root@$REMOTE_HOST" exit 2>/dev/null; then
  echo "✅ Key-based auth succeeded"
  SSH_CONNECT() { KEY_SSH "root@$REMOTE_HOST" "$@"; }
else
  echo "⚠️  Key auth failed — attempting password auth..."
  if ! PASS_SSH "root@$REMOTE_HOST" exit 2>/dev/null; then
    echo "❌ Cannot connect to $REMOTE_HOST — both auth methods failed"
    exit 1
  fi

  echo "✅ Password auth succeeded"
  SSH_CONNECT() { PASS_SSH "root@$REMOTE_HOST" "$@"; }

  echo "🔑 Installing SSH public key for future runs..."
  sshpass -p "$SSH_PASSWORD" ssh-copy-id \
    -o StrictHostKeyChecking=no \
    -i ~/.ssh/id_ed25519 \
    "root@$REMOTE_HOST" && \
    echo "✅ Key installed — password auth won't be needed next run" || \
    echo "⚠️  ssh-copy-id failed — continuing with password auth"
fi

# ══════════════════════════════════════════════════════════════════════════════
# CAPTURE PRIVATE KEY FOR REMOTE INJECTION
# ══════════════════════════════════════════════════════════════════════════════
PRIVATE_KEY_CONTENTS=$(cat ~/.ssh/id_ed25519)

# ══════════════════════════════════════════════════════════════════════════════
# REMOTE SESSION
# ══════════════════════════════════════════════════════════════════════════════
echo "🚀 Starting remote session on $REMOTE_HOST..."

SSH_CONNECT bash << EOF
set -euo pipefail

COMPOSE_DIR="$COMPOSE_DIR"
MOUNT_POINT="$MOUNT_POINT"
MOUNT_REMOTE="$MOUNT_REMOTE"
RESTIC_REPO="$RESTIC_REPO"
MODE="$MODE"
export RESTIC_PASSWORD="$RESTIC_PASSWORD"
export RESTIC_REPOSITORY="\$RESTIC_REPO"

log()  { echo "  \$1"; }
step() { echo ""; echo "▶ \$1"; }

has_compose() {
  [ -f "\$1/docker-compose.yml" ] || [ -f "\$1/compose.yml" ]
}

find_compose_dir() {
  if has_compose "\$COMPOSE_DIR"; then
    echo "\$COMPOSE_DIR"
  elif has_compose "/home/zeshan/docker"; then
    echo "/home/zeshan/docker"
  else
    echo ""
  fi
}

# ── 1. Install Dependencies ───────────────────────────────────────────────────
step "Installing dependencies"

log "📦 Updating package lists..."
apt-get update -qq

log "📦 Installing packages..."
apt-get install -y --no-install-recommends \
  curl \
  wget \
  ca-certificates \
  bash \
  coreutils \
  procps \
  openssh-server \
  sshfs \
  restic \
  fuse3
log "✅ Packages installed"

# ── 2. Docker ─────────────────────────────────────────────────────────────────
step "Docker"
if ! command -v docker &>/dev/null; then
  log "🐋 Installing Docker..."
  curl -fsSL https://get.docker.com | sh
  systemctl enable --now docker
  log "✅ Docker installed"
else
  log "✅ Docker already installed (\$(docker --version))"
fi

# ── 3. Migrate legacy zeshan paths ───────────────────────────────────────────
step "Path migration"
if [ -d "/home/zeshan/docker" ] && [ ! -d "/root/docker" ]; then
  log "📦 Migrating /home/zeshan/docker → /root/docker..."
  cp -r /home/zeshan/docker /root/docker
  log "✅ Migration complete"
elif [ -d "/root/docker" ]; then
  log "✅ /root/docker already exists"
else
  log "⚠️  No compose directory found yet"
fi

# ── 4. FUSE ───────────────────────────────────────────────────────────────────
step "FUSE config"
grep -q "^user_allow_other" /etc/fuse.conf 2>/dev/null || \
  echo "user_allow_other" >> /etc/fuse.conf
log "✅ FUSE configured"

# ── 5. Storage Mount ──────────────────────────────────────────────────────────
step "Storage mount"
if mountpoint -q "\$MOUNT_POINT"; then
  log "⚠️  Already mounted — unmounting first..."
  umount -l "\$MOUNT_POINT"
fi
mkdir -p "\$MOUNT_POINT"

MOUNT_KEY="\$(mktemp /root/.ssh/mount_key.XXXXXX)"
chmod 600 "\$MOUNT_KEY"
cat > "\$MOUNT_KEY" << 'PRIVKEY'
$PRIVATE_KEY_CONTENTS
PRIVKEY
chmod 600 "\$MOUNT_KEY"
trap 'rm -f \$MOUNT_KEY' EXIT

log "🔗 Mounting \$MOUNT_REMOTE..."
sshfs \
  -o StrictHostKeyChecking=no \
  -o IdentityFile="\$MOUNT_KEY" \
  -o allow_other \
  -o reconnect \
  -o ServerAliveInterval=15 \
  -o ServerAliveCountMax=3 \
  "\$MOUNT_REMOTE" "\$MOUNT_POINT"

rm -f "\$MOUNT_KEY"

if ! mountpoint -q "\$MOUNT_POINT"; then
  echo "❌ Mount failed!"
  exit 1
fi
log "✅ \$MOUNT_POINT mounted from \$MOUNT_REMOTE"
# ── 6. Persist mount in fstab ─────────────────────────────────────────────────
step "Persisting mount in fstab"

PERSISTENT_KEY="/root/.ssh/sshfs_mount_key"
cat > "\$PERSISTENT_KEY" << 'PRIVKEY'
$PRIVATE_KEY_CONTENTS
PRIVKEY
chmod 600 "\$PERSISTENT_KEY"

if grep -q "n.h-y.st:/mnt/data" /etc/fstab; then
  log "✅ fstab entry already exists — skipping"
else
  echo "root@n.h-y.st:/mnt/data  /mnt/data  fuse.sshfs  IdentityFile=/root/.ssh/sshfs_mount_key,StrictHostKeyChecking=no,allow_other,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,_netdev,x-systemd.automount  0  0" >> /etc/fstab
  log "✅ fstab entry added"
fi

grep "n.h-y.st" /etc/fstab
# ── 6. Restic Repo ────────────────────────────────────────────────────────────
step "Restic repository"
if ! restic snapshots &>/dev/null; then
  log "📦 Initialising new restic repository..."
  restic init
  log "✅ Repository initialised"
else
  log "✅ Repository already exists"
  restic snapshots --compact
fi

# ── 7. Backup or Restore ──────────────────────────────────────────────────────
step "Task: \$MODE"

if [ "\$MODE" == "RESTORE" ]; then

  log "📋 Available snapshots:"
  restic snapshots

  log "⚠️  Restoring in 5 seconds — Ctrl+C to abort..."
  sleep 5

  log "⏬ Restoring latest snapshot..."
  mkdir -p /root/docker /var/lib/docker/volumes
  restic restore latest --target /

  if [ -d "/home/zeshan/docker" ] && [ ! -d "/root/docker" ]; then
    log "📦 Moving restored zeshan paths to /root/docker..."
    cp -r /home/zeshan/docker /root/docker
  fi

  log "✅ Restore complete"

  ACTIVE_COMPOSE="\$(find_compose_dir)"
  if [ -n "\$ACTIVE_COMPOSE" ]; then
    log "🐳 Starting Docker services from \$ACTIVE_COMPOSE..."
    cd "\$ACTIVE_COMPOSE" && docker compose up -d
    log "✅ Services started"
    docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
  else
    log "⚠️  No compose file found — skipping docker compose up"
  fi

else  # BACKUP

  ACTIVE_COMPOSE="\$(find_compose_dir)"

  if [ -n "\$ACTIVE_COMPOSE" ]; then
    log "⏸️  Stopping services for consistent backup..."
    cd "\$ACTIVE_COMPOSE" && docker compose stop
  else
    log "⚠️  No compose file found — skipping stop"
  fi

  log "💾 Running backup..."
  BACKUP_PATHS="/var/lib/docker/volumes"
  [ -d "/root/docker" ]        && BACKUP_PATHS="\$BACKUP_PATHS /root/docker"
  [ -d "/home/zeshan/docker" ] && BACKUP_PATHS="\$BACKUP_PATHS /home/zeshan/docker"

  restic backup \
    --tag automated \
    --tag "\$(date +%Y-%m-%d)" \
    --exclude="*.log" \
    --exclude="*.tmp" \
    --exclude="*.cache" \
    \$BACKUP_PATHS

  log "✂️  Pruning old snapshots..."
  restic forget \
    --tag automated \
    --keep-daily 7 \
    --keep-weekly 4 \
    --keep-monthly 3 \
    --prune

  log "🔍 Verifying repository integrity..."
  restic check --read-data-subset=5%

  if [ -n "\$ACTIVE_COMPOSE" ]; then
    log "▶️  Restarting services..."
    cd "\$ACTIVE_COMPOSE" && docker compose start
    log "✅ Services restarted"
    docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
  fi

fi

# ── 8. Cleanup ────────────────────────────────────────────────────────────────
step "Cleanup"
umount "\$MOUNT_POINT" && log "✅ \$MOUNT_POINT unmounted"

echo "
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✅ \$MODE completed successfully
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"
EOF

SCRIPT

RUN chmod +x /app/run.sh
ENTRYPOINT ["/app/run.sh"]