#!/usr/bin/env bash
set -euo pipefail

########################################
# merge_rollback_partial_worlds (PostgreSQL)
#
# 參數:
#   $1: merge_setup.ini 絕對路徑
#   $2: BACKUP_TAG (run_merge_n1/run_merge_n1_echo 內傳入的 ${FILE_NAME}_Pre)
#
# 行為:
#   - source $HOME/bin/load_merge_db_setup
#   - load_merge_db_setup <merge_setup.ini>
#   - 取得 AccountDB 連線資訊
#   - 依 world_order 由上而下取得所有 WorldID
#     * 第一個視為 target_world_id，忽略（worlds rollback 不含 target）
#     * 其餘視為 source_world_ids，轉成逗點分隔字串 source_world_ids_str
#   - 另外把 world_order 全部 WorldID (含 target + source) 組成 world_order_ids_str
#
# 1) 從「_Pre AccountDB」讀回 worlds 指定 id 的資料，寫回「當下 AccountDB」
#    - 不用 pg_dump --where（你環境不支援）
#    - 改用 psql \copy 匯出 CSV，再 \copy 匯入
#    - 匯入前先 DELETE 避免 PK 衝突
# 2) fake_worlds 回復:
#    - 從 backup DB 匯出：SELECT * FROM fake_worlds WHERE real_world_id IN (world_order_ids_str)
#    - 在主 DB 先刪除：DELETE FROM fake_worlds WHERE id IN (world_order_ids_str)
#      再刪除：DELETE FROM fake_worlds WHERE real_world_id IN (world_order_ids_str)
#    - 再匯入 fake_worlds CSV
#
# 備註:
#   - backup db 名稱：<AccountDBName>_<BACKUP_TAG>
#     例如 AccountDBName=N1Account，BACKUP_TAG=20251212_2_Pre
#     => backup db = N1Account_20251212_2_Pre
########################################

if [ "$#" -ne 2 ]; then
  echo "Usage: $0 <ABS_merge_setup.ini> <BACKUP_TAG: \${FILE_NAME}_Pre>" >&2
  exit 1
fi

INI_PATH="$1"
BACKUP_TAG="$2"

if [ ! -f "$INI_PATH" ]; then
  echo "Error: merge_setup.ini not found: $INI_PATH" >&2
  exit 1
fi
if [ ! -s "$INI_PATH" ]; then
  echo "Error: merge_setup.ini is empty: $INI_PATH" >&2
  exit 1
fi
if [ -z "$BACKUP_TAG" ]; then
  echo "Error: BACKUP_TAG is empty." >&2
  exit 1
fi

LOADER="$HOME/bin/load_merge_db_setup"
if [ ! -f "$LOADER" ]; then
  echo "Error: loader not found: $LOADER" >&2
  exit 1
fi

# shellcheck source=/dev/null
source "$LOADER"

for fn in load_merge_db_setup get_accountdb_value join_by_comma; do
  if ! declare -F "$fn" >/dev/null 2>&1; then
    echo "Error: function '$fn' not found after sourcing $LOADER" >&2
    exit 1
  fi
done

load_merge_db_setup "$INI_PATH"

ACCOUNT_HOST="$(get_accountdb_value "AccountDBIP")"
ACCOUNT_DB="$(get_accountdb_value "AccountDBName")"
ACCOUNT_USER="$(get_accountdb_value "AccountDBUser")"
ACCOUNT_PASS="$(get_accountdb_value "AccountDBPW")"
ACCOUNT_PORT="$(get_accountdb_value "AccountDBPort")"
ACCOUNT_PORT="${ACCOUNT_PORT:-5432}"

if [ -z "$ACCOUNT_HOST" ] || [ -z "$ACCOUNT_DB" ] || [ -z "$ACCOUNT_USER" ]; then
  echo "Error: AccountDB connection info missing from $INI_PATH" >&2
  echo "  host='$ACCOUNT_HOST' db='$ACCOUNT_DB' user='$ACCOUNT_USER' port='$ACCOUNT_PORT'" >&2
  exit 1
fi

if [ "${#world_order[@]}" -lt 2 ]; then
  echo "Error: need at least 2 WorldID entries in merge_setup.ini." >&2
  echo "  world_order count: ${#world_order[@]}" >&2
  exit 1
fi

target_world_id="${world_order[0]}"
source_world_ids=( "${world_order[@]:1}" )

# source worlds 去重
declare -A SEEN=()
declare -a source_world_ids_uniq=()
for wid in "${source_world_ids[@]}"; do
  if [[ -z "${SEEN[$wid]+x}" ]]; then
    SEEN["$wid"]=1
    source_world_ids_uniq+=( "$wid" )
  fi
done

if [ "${#source_world_ids_uniq[@]}" -eq 0 ]; then
  echo "No source world ids after ignoring target_world_id=${target_world_id}. Nothing to do."
  exit 0
fi

# world_order 全部 ids (含 target + source) 去重
declare -A SEEN_ALL=()
declare -a world_order_ids_uniq=()
for wid in "${world_order[@]}"; do
  if [[ -z "${SEEN_ALL[$wid]+x}" ]]; then
    SEEN_ALL["$wid"]=1
    world_order_ids_uniq+=( "$wid" )
  fi
done

source_world_ids_str="$(join_by_comma "${source_world_ids_uniq[@]}")"
world_order_ids_str="$(join_by_comma "${world_order_ids_uniq[@]}")"
BACKUP_DB="${ACCOUNT_DB}_${BACKUP_TAG}"

export PGHOST="$ACCOUNT_HOST"
export PGPORT="$ACCOUNT_PORT"
export PGUSER="$ACCOUNT_USER"
export PGPASSWORD="${ACCOUNT_PASS:-}"

echo "== merge_rollback_partial_worlds (PostgreSQL) =="
echo "INI              : $INI_PATH"
echo "AccountDB Host   : $ACCOUNT_HOST:$ACCOUNT_PORT"
echo "AccountDB Name   : $ACCOUNT_DB"
echo "Backup Tag       : $BACKUP_TAG"
echo "Backup Pre DB    : $BACKUP_DB"
echo "target_world_id  : $target_world_id (ignored for worlds rollback)"
echo "source_world_ids : $source_world_ids_str"
echo "world_order_ids  : $world_order_ids_str"
echo

db_exists="$(
  psql -d postgres -Atqc \
    "SELECT 1 FROM pg_database WHERE datname='${BACKUP_DB}' LIMIT 1;" 2>/dev/null || true
)"
if [ "$db_exists" != "1" ]; then
  echo "Error: backup database not found: $BACKUP_DB" >&2
  exit 1
fi

expected_cnt="${#source_world_ids_uniq[@]}"
actual_cnt="$(
  psql -d "$BACKUP_DB" -Atqc \
    "SELECT COUNT(*) FROM worlds WHERE id IN (${source_world_ids_str});" 2>/dev/null || true
)"
if ! [[ "$actual_cnt" =~ ^[0-9]+$ ]]; then
  echo "Error: failed to query backup worlds count from $BACKUP_DB" >&2
  exit 1
fi
if [ "$actual_cnt" -ne "$expected_cnt" ]; then
  echo "Error: backup worlds rows count mismatch in $BACKUP_DB" >&2
  echo "  expected: $expected_cnt" >&2
  echo "  actual  : $actual_cnt" >&2
  echo "  ids     : $source_world_ids_str" >&2
  exit 1
fi

tmp_worlds_csv="$(mktemp /tmp/worlds_restore.XXXXXX.csv)"
tmp_fake_worlds_csv="$(mktemp /tmp/fake_worlds_restore.XXXXXX.csv)"
cleanup() { rm -f "$tmp_worlds_csv" "$tmp_fake_worlds_csv"; }
trap cleanup EXIT

# 匯出 worlds（source worlds）
psql -d "$BACKUP_DB" -v ON_ERROR_STOP=1 -q <<SQL > "$tmp_worlds_csv"
\\copy (SELECT * FROM worlds WHERE id IN (${source_world_ids_str}) ORDER BY id) TO STDOUT WITH (FORMAT csv)
SQL

if [ ! -s "$tmp_worlds_csv" ]; then
  echo "Error: exported worlds CSV is empty. Abort." >&2
  exit 1
fi

# 匯出 fake_worlds（依 real_world_id，使用 world_order 全部 ids）
psql -d "$BACKUP_DB" -v ON_ERROR_STOP=1 -q <<SQL > "$tmp_fake_worlds_csv"
\\copy (SELECT * FROM fake_worlds WHERE real_world_id IN (${world_order_ids_str})) TO STDOUT WITH (FORMAT csv)
SQL
# 注意：fake_worlds 可能是 0 rows，允許 CSV 為空檔，不中止

psql -d "$ACCOUNT_DB" -v ON_ERROR_STOP=1 <<SQL
BEGIN;

-- worlds：回復 source worlds
DELETE FROM worlds WHERE id IN (${source_world_ids_str});
\\copy worlds FROM '${tmp_worlds_csv}' WITH (FORMAT csv);

-- fake_worlds：清理後回復（以 world_order ids 為範圍）
DELETE FROM fake_worlds WHERE id IN (${world_order_ids_str});
DELETE FROM fake_worlds WHERE real_world_id IN (${world_order_ids_str});
\\copy fake_worlds FROM '${tmp_fake_worlds_csv}' WITH (FORMAT csv);

COMMIT;
SQL

echo "Rollback done."

