#!/bin/bash
set -euo pipefail

# ================================================================
# Backup script for Matrix instances on yc-playground cluster
# ================================================================
# Backs up the old chart (matrix-2.9.17) prod instances:
#   t0rt1k.tech, roglog.space, uretra.space
#
# Usage: ./backup-yc-playground.sh <name> [--no-downtime]
# Example: ./backup-yc-playground.sh t0rt1k
#          ./backup-yc-playground.sh t0rt1k --no-downtime  (test, no scaling)
# ================================================================

readonly YC_CONTEXT="yc-playground"
readonly K="${KUBECTL:-kubectl} --context ${YC_CONTEXT}"
readonly BACKUP_BASE="$(dirname "$(realpath "$0")")/../backups"
readonly TIMESTAMP="$(date +%Y%m%d-%H%M%S)"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log()  { echo -e "${GREEN}[$(date +%H:%M:%S)]${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] WARN:${NC} $*"; }
err()  { echo -e "${RED}[$(date +%H:%M:%S)] ERROR:${NC} $*"; }

# -------------------------------------------------------------------
# Parse args
# -------------------------------------------------------------------
DOWNTIME=true
NAME=""
for arg in "$@"; do
    case "$arg" in
        --no-downtime) DOWNTIME=false ;;
        *) NAME="$arg" ;;
    esac
done

if [ -z "${NAME}" ]; then
    echo "Usage: $0 <name> [--no-downtime]"
    echo "  name: t0rt1k | roglog | uretra"
    echo "  --no-downtime: skip scale up/down (test run)"
    exit 1
fi

readonly NS="matrix-${NAME}"
readonly BACKUP_DIR="${BACKUP_BASE}/matrix-${NAME}-${TIMESTAMP}"

# Synapse labels
readonly SYNAPSE_LABEL="app.kubernetes.io/instance=chat,app.kubernetes.io/name=matrix"
# MAS labels
readonly MAS_LABEL="app=mas"
readonly MAS_PG_LABEL="app=mas-postgresql"

# -------------------------------------------------------------------
# Prerequisites
# -------------------------------------------------------------------
log "=== Backing up ${NS} (downtime=${DOWNTIME}) ==="

if ! ${K} get ns "${NS}" >/dev/null 2>&1; then
    err "Namespace ${NS} not found on yc-playground."
    exit 1
fi

mkdir -p "${BACKUP_DIR}"
log "Backup directory: ${BACKUP_DIR}"

# -------------------------------------------------------------------
# Step 1: Backup Synapse media
# -------------------------------------------------------------------
log "=== Step 1: Backing up Synapse media ==="

SYNAPSE_POD=$(${K} -n "${NS}" get pods -l "${SYNAPSE_LABEL}" -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}' 2>/dev/null)

if [ -n "${SYNAPSE_POD}" ]; then
    log "Synapse pod: ${SYNAPSE_POD}"
    # Check if media directory exists
    if ${K} exec -n "${NS}" "${SYNAPSE_POD}" -- test -d /data/media_store 2>/dev/null; then
        ${K} exec -n "${NS}" "${SYNAPSE_POD}" -- tar czf /tmp/synapse-media.tar.gz -C /data media_store/
        ${K} cp "${NS}/${SYNAPSE_POD}:/tmp/synapse-media.tar.gz" "${BACKUP_DIR}/synapse-media.tar.gz" 2>/dev/null || \
            ${K} cp "${NS}/${SYNAPSE_POD}:tmp/synapse-media.tar.gz" "${BACKUP_DIR}/synapse-media.tar.gz"
        ${K} exec -n "${NS}" "${SYNAPSE_POD}" -- rm -f /tmp/synapse-media.tar.gz
        log "Media saved: $(du -h "${BACKUP_DIR}/synapse-media.tar.gz" | cut -f1)"
    else
        warn "/data/media_store not found in Synapse pod."
    fi
else
    warn "No running Synapse pod found — skipping media backup."
fi

# -------------------------------------------------------------------
# Step 2: Stop Synapse + MAS
# -------------------------------------------------------------------
if ${DOWNTIME}; then
    log "=== Step 2: Stopping Synapse + MAS ==="

    SYNAPSE_READY=$(${K} -n "${NS}" get deploy chat-matrix -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo "0")
    MAS_READY=$(${K} -n "${NS}" get deploy mas -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo "0")

    if [ "${SYNAPSE_READY}" != "0" ]; then
        ${K} -n "${NS}" scale deploy chat-matrix --replicas=0
        log "Synapse scaled to 0."
    else
        log "Synapse already scaled to 0."
    fi

    if [ "${MAS_READY}" != "0" ]; then
        ${K} -n "${NS}" scale deploy mas --replicas=0
        log "MAS scaled to 0."
    else
        log "MAS already scaled to 0."
    fi

    ${K} -n "${NS}" wait --for=delete pod -l "${SYNAPSE_LABEL}" --timeout=120s 2>/dev/null || warn "Synapse may still be terminating."
    ${K} -n "${NS}" wait --for=delete pod -l "${MAS_LABEL}" --timeout=120s 2>/dev/null || warn "MAS may still be terminating."
    log "Synapse + MAS stopped."
else
    log "=== Step 2: Skipping downtime (--no-downtime) ==="
fi

# -------------------------------------------------------------------
# Step 3: Dump Synapse PostgreSQL
# -------------------------------------------------------------------
log "=== Step 3: Dumping Synapse PostgreSQL ==="

# Get the postgres password from the secret
SYNAPSE_PG_PW=$(${K} -n "${NS}" get secret chat-postgresql -o jsonpath='{.data.postgres-password}' 2>/dev/null | base64 -d)

if [ -z "${SYNAPSE_PG_PW}" ]; then
    SYNAPSE_PG_PW=$(${K} -n "${NS}" get secret chat-postgresql -o jsonpath='{.data.password}' 2>/dev/null | base64 -d)
fi

if [ -z "${SYNAPSE_PG_PW}" ]; then
    warn "Could not read chat-postgresql secret — trying env var from pod."
    SYNAPSE_PG_PW=$(${K} exec -n "${NS}" chat-postgresql-0 -c postgresql -- bash -c 'echo $POSTGRES_POSTGRES_PASSWORD' 2>/dev/null)
fi

${K} exec -n "${NS}" chat-postgresql-0 -c postgresql -- bash -c "env PGPASSWORD='${SYNAPSE_PG_PW}' pg_dump -U postgres -d matrix -f /bitnami/postgresql/data/dump.sql" 2>&1
${K} cp "${NS}/chat-postgresql-0:/bitnami/postgresql/data/dump.sql" "${BACKUP_DIR}/dump-synapse.sql" 2>/dev/null || true
${K} exec -n "${NS}" chat-postgresql-0 -c postgresql -- rm -f /bitnami/postgresql/data/dump.sql
log "Synapse dump saved: ${BACKUP_DIR}/dump-synapse.sql ($(wc -c < "${BACKUP_DIR}/dump-synapse.sql") bytes)"

# -------------------------------------------------------------------
# Step 4: Dump MAS PostgreSQL
# -------------------------------------------------------------------
log "=== Step 4: Dumping MAS PostgreSQL ==="

MAS_PG_POD=$(${K} -n "${NS}" get pods -l "${MAS_PG_LABEL}" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null)

if [ -n "${MAS_PG_POD}" ]; then
    MAS_PG_PW=$(${K} exec -n "${NS}" "${MAS_PG_POD}" -c postgresql -- bash -c 'echo $POSTGRESQL_PASSWORD' 2>/dev/null)
    MAS_DB=$(${K} exec -n "${NS}" "${MAS_PG_POD}" -c postgresql -- bash -c 'echo $POSTGRESQL_DATABASE' 2>/dev/null)

    if [ -n "${MAS_PG_PW}" ]; then
        ${K} exec -n "${NS}" "${MAS_PG_POD}" -c postgresql -- bash -c "env PGPASSWORD='${MAS_PG_PW}' pg_dump -U '${MAS_DB:-mas}' -d '${MAS_DB:-mas}' -f /bitnami/postgresql/data/dump.sql" 2>&1
        ${K} cp "${NS}/${MAS_PG_POD}:/bitnami/postgresql/data/dump.sql" "${BACKUP_DIR}/dump-mas.sql" 2>/dev/null || true
        ${K} exec -n "${NS}" "${MAS_PG_POD}" -c postgresql -- rm -f /bitnami/postgresql/data/dump.sql
        log "MAS dump saved: ${BACKUP_DIR}/dump-mas.sql ($(wc -c < "${BACKUP_DIR}/dump-mas.sql") bytes)"
    else
        warn "Could not read MAS PG password — skipping MAS dump."
    fi
else
    warn "No MAS PG pod found — skipping MAS dump."
fi

# -------------------------------------------------------------------
# Step 5: Export secrets
# -------------------------------------------------------------------
log "=== Step 5: Exporting secrets ==="

for secret in chat-matrix chat-postgresql mas matrixrtc-livekit; do
    if ${K} -n "${NS}" get secret "${secret}" >/dev/null 2>&1; then
        ${K} -n "${NS}" get secret "${secret}" -o yaml > "${BACKUP_DIR}/secret-${secret}.yaml"
        log "Secret saved: secret-${secret}.yaml"
    else
        warn "Secret '${secret}' not found."
    fi
done

# -------------------------------------------------------------------
# Step 6: Restart Synapse + MAS
# -------------------------------------------------------------------
if ${DOWNTIME}; then
    log "=== Step 6: Restarting Synapse + MAS ==="
    ${K} -n "${NS}" scale deploy chat-matrix --replicas=1 2>/dev/null || warn "Could not scale Synapse."
    ${K} -n "${NS}" scale deploy mas --replicas=1 2>/dev/null || warn "Could not scale MAS."
    log "Synapse + MAS restarted."
else
    log "=== Step 6: Skipped (--no-downtime) ==="
fi

# -------------------------------------------------------------------
# Step 7: Write README
# -------------------------------------------------------------------
log "=== Step 7: Writing README ==="

cat > "${BACKUP_DIR}/README.txt" << READEOF
Backup for ${NS} — ${TIMESTAMP}
==================================

Instance: ${NAME} (namespace: ${NS})
Chart:    matrix-2.9.17 (old chart, NOT ESS)
Dump PG:  Synapse (chat-postgresql) + MAS (mas-postgresql)

Files:
  dump-synapse.sql      Synapse PostgreSQL dump (pg_dump -U postgres -d matrix)
  dump-mas.sql          MAS PostgreSQL dump (pg_dump -U mas -d mas)
  synapse-media.tar.gz  Synapse media files (/data/media_store/)
  secret-chat-matrix.yaml       Synapse secrets (signing.key, macaroon, etc.)
  secret-chat-postgresql.yaml   PG passwords
  secret-mas.yaml               MAS secrets (encryption-key, signing-key, shared-secret)
  secret-matrixrtc-livekit.yaml LiveKit secrets

CRITICAL for restore:
  - secret-chat-matrix.yaml  (SYNAPSE_SIGNING_KEY for federation identity)
  - secret-mas.yaml          (MAS encryption-key for user sessions)
  - dump-synapse.sql         (all user data, rooms, messages)
  - dump-mas.sql             (MAS user auth data)

Migration to ESS chart notes:
  - The old chart uses separate Helm releases per component (chat, element-call, livekit).
  - ESS bundles everything into the matrix-stack chart.
  - PostgreSQL is external (CNPG) on the new cluster.
  - MAS keys must be restored EXACTLY as-is for user auth to work.
  - The Synapse signing.key MUST match the federation identity.
READEOF

log "README saved."

# -------------------------------------------------------------------
# Summary
# -------------------------------------------------------------------
cat <<SUMMARY

${GREEN}========================================${NC}
${GREEN}  Backup Complete: ${NS}${NC}
${GREEN}========================================${NC}

  Directory: ${BACKUP_DIR}
  Size:      $(du -sh "${BACKUP_DIR}" | cut -f1)
  Downtime:  ${DOWNTIME}

SUMMARY
