#!/usr/bin/env bash
# Remap Supabase Storage objects in S3 for STORAGE_TENANT_ID=stub (Datafy self-hosted).
#
# Storage 1.60+ key layout (confirmed by Studio upload):
#   s3://datafy-prod-supabase-storage/stub/<bucket_id>/<name>/<version>
#   (if version is null: stub/<bucket_id>/<name>)
#
# rclone leaves objects at:
#   s3://datafy-prod-supabase-storage/<bucket_id>/<name>
#
# This script COPIES (never deletes). Idempotent. Dry-run by default.
# WRONG older layout (do not use): .../<name>-$v-<version>
#
# Usage:
#   ~/migration/remap_storage_s3_keys.sh
#   ~/migration/remap_storage_s3_keys.sh --execute --jobs 32
#   nohup ~/migration/remap_storage_s3_keys.sh --execute --jobs 32 \
#     > ~/migration/remap-execute.out 2>&1 &
#
set -euo pipefail

EXECUTE=0
FILTER_BUCKET=""
FILTER_PREFIX=""
JOBS=32
REGION="${AWS_REGION:-eu-west-1}"
LOG="${HOME}/migration/remap_storage_s3.log"
MANIFEST="${HOME}/migration/remap_keys.tsv"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --execute|-x) EXECUTE=1; shift ;;
    --dry-run) EXECUTE=0; shift ;;
    --bucket) FILTER_BUCKET="$2"; shift 2 ;;
    --prefix) FILTER_PREFIX="$2"; shift 2 ;;
    --jobs|-j) JOBS="$2"; shift 2 ;;
    --region) REGION="$2"; shift 2 ;;
    --log) LOG="$2"; shift 2 ;;
    *) echo "Unknown arg: $1" >&2; exit 1 ;;
  esac
done

mkdir -p "$(dirname "$LOG")" "$(dirname "$MANIFEST")"
touch "$LOG"

env_get() {
  local key=$1 file=${2:-"${HOME}/supabase-project/.env"}
  [[ -f "$file" ]] || return 1
  local line
  line=$(grep -E "^${key}=" "$file" | tail -1) || return 1
  line=${line#${key}=}
  line=${line#$'\r'}
  if [[ "$line" == \"*\" ]]; then line=${line:1:-1}; fi
  if [[ "$line" == \'*\' ]]; then line=${line:1:-1}; fi
  printf '%s' "$line"
}

load_db_env() {
  if [[ -f "${HOME}/migration/db-env.sh" ]]; then
    # shellcheck disable=SC1091
    source "${HOME}/migration/db-env.sh"
  else
    export PGHOST; PGHOST=$(env_get POSTGRES_HOST) || true
    export PGPORT; PGPORT=$(env_get POSTGRES_PORT || echo 5432)
    export PGDATABASE; PGDATABASE=$(env_get POSTGRES_DB || echo postgres)
    export PGUSER=postgres
    export PGSSLMODE=require
    : "${PGHOST:?Set POSTGRES_HOST in ~/supabase-project/.env or use ~/migration/db-env.sh}"
    if [[ -z "${PGPASSWORD:-}" ]]; then
      PGPASSWORD=$(aws secretsmanager get-secret-value \
        --secret-id 'rds!db-d6f075f5-94d0-4ce6-8162-a3b20397d94c' \
        --region "$REGION" \
        --query SecretString --output text | jq -r '.password')
      export PGPASSWORD
    fi
  fi
  local g t
  g=$(env_get GLOBAL_S3_BUCKET || true)
  t=$(env_get STORAGE_TENANT_ID || true)
  [[ -n "$g" ]] && GLOBAL_S3_BUCKET=$g
  [[ -n "$t" ]] && STORAGE_TENANT_ID=$t
}

sql_literal() {
  local s=$1
  s=${s//\'/\'\'}
  printf "'%s'" "$s"
}

load_db_env

S3_BUCKET="${GLOBAL_S3_BUCKET:-datafy-prod-supabase-storage}"
TENANT="${STORAGE_TENANT_ID:-stub}"

if [[ -z "$TENANT" || "$TENANT" == "your-tenant-id" ]]; then
  echo "ERROR: STORAGE_TENANT_ID empty/placeholder" >&2
  exit 1
fi

where="TRUE"
if [[ -n "$FILTER_BUCKET" ]]; then
  where="bucket_id = $(sql_literal "$FILTER_BUCKET")"
fi
if [[ -n "$FILTER_PREFIX" ]]; then
  local_pref=$(sql_literal "${FILTER_PREFIX}%")
  if [[ "$where" == "TRUE" ]]; then
    where="name LIKE ${local_pref}"
  else
    where+=" AND name LIKE ${local_pref}"
  fi
fi

SQL="SELECT bucket_id, name, COALESCE(version::text, '')
FROM storage.objects
WHERE ${where}
ORDER BY bucket_id, name;"

echo "=== remap_storage_s3_keys (name/version layout) ===" | tee -a "$LOG"
echo "mode: $([[ $EXECUTE -eq 1 ]] && echo EXECUTE || echo DRY-RUN) jobs=$JOBS" | tee -a "$LOG"
echo "s3_bucket=$S3_BUCKET tenant=$TENANT region=$REGION" | tee -a "$LOG"
echo "filter bucket=${FILTER_BUCKET:-*} prefix=${FILTER_PREFIX:-*}" | tee -a "$LOG"

# Build manifest: src_key <TAB> dst_key
: > "$MANIFEST"
planned=0
while IFS=$'\t' read -r bucket_id name version; do
  [[ -n "${bucket_id:-}" ]] || continue
  src_key="${bucket_id}/${name}"
  if [[ -n "$version" ]]; then
    dst_key="${TENANT}/${bucket_id}/${name}/${version}"
  else
    dst_key="${TENANT}/${bucket_id}/${name}"
  fi
  printf '%s\t%s\n' "$src_key" "$dst_key" >> "$MANIFEST"
  planned=$((planned + 1))
done < <(psql -At -F $'\t' -c "$SQL")

echo "manifest=$MANIFEST rows=$planned" | tee -a "$LOG"

if [[ $EXECUTE -eq 0 ]]; then
  head -5 "$MANIFEST" | tee -a "$LOG"
  echo "Dry-run only. Re-run with --execute to copy (server-side, parallel)."
  exit 0
fi

export S3_BUCKET REGION LOG
# Parallel server-side copies (same bucket — data does not download to EC2)
copy_one() {
  local src_key=$1 dst_key=$2
  if aws s3api head-object --bucket "$S3_BUCKET" --key "$dst_key" --region "$REGION" >/dev/null 2>&1; then
    echo "SKIP $dst_key" | tee -a "$LOG"
    return 0
  fi
  if ! aws s3api head-object --bucket "$S3_BUCKET" --key "$src_key" --region "$REGION" >/dev/null 2>&1; then
    echo "MISSING $src_key" | tee -a "$LOG"
    return 0
  fi
  if aws s3 cp "s3://${S3_BUCKET}/${src_key}" "s3://${S3_BUCKET}/${dst_key}" --region "$REGION" >>"$LOG" 2>&1; then
    echo "OK $src_key" | tee -a "$LOG"
  else
    echo "FAIL $src_key" | tee -a "$LOG"
  fi
}
export -f copy_one

if command -v parallel >/dev/null 2>&1; then
  parallel -j "$JOBS" --colsep $'\t' copy_one {1} {2} :::: "$MANIFEST"
else
  echo "GNU parallel not found — using xargs -P $JOBS" | tee -a "$LOG"
  cat "$MANIFEST" | xargs -P "$JOBS" -n 1 -d '\n' bash -c '
    row="$1"
    src_key="${row%%	*}"
    dst_key="${row#*	}"
    copy_one "$src_key" "$dst_key"
  ' _
fi

echo "=== DONE — see $LOG ===" | tee -a "$LOG"
echo "NOTE: Old wrong keys .../\$v-... can be deleted later; they are unused."
