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

########################################
# merge_update_guild_race_data (PostgreSQL)
#
# 參數:
#   $1: merge_setup.ini 絕對路徑
#
# 行為:
#   - source $HOME/bin/load_merge_db_setup
#   - load_merge_db_setup <merge_setup.ini>
#   - 取得 GameDB 連線資訊
#   - 依 world_order:
#       * 第一個視為 target_world_id
#       * 其餘視為 source_world_ids（去重但保序）
#
#   1) 迴圈外：normalize guild_race_data
#      - 確保 fightrecordata.fightrecords / defendrecordata.defendrecords 存在且為 object {}
#   2) 迴圈內：for each source_world_id
#      - 只更新 JSON 內確實命中 source_world_id 的列
#      - 更新 challengerworldID / targetworldID 為 target_world_id（JSON 字串）
#      - 輸出每段 UPDATE 影響列數
########################################

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

INI_PATH="$1"

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

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_gamedb_value check_gamedb_connection; 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"

GAME_HOST="$(get_gamedb_value "GameDBIP")"
GAME_DB="$(get_gamedb_value "GameDB")"
GAME_USER="$(get_gamedb_value "GameDBUser")"
GAME_PASS="$(get_gamedb_value "GameDBPassword")"
GAME_PORT="$(get_gamedb_value "GameDBPort")"
GAME_PORT="${GAME_PORT:-5432}"

if [ -z "$GAME_HOST" ] || [ -z "$GAME_DB" ] || [ -z "$GAME_USER" ]; then
  echo "Error: GameDB connection info missing from $INI_PATH" >&2
  echo "  host='$GAME_HOST' db='$GAME_DB' user='$GAME_USER' port='$GAME_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}" )

# 去重但保序
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

# 基本安全檢查：世界 ID 預期為數字（避免注入 & 非預期字串）
if ! [[ "$target_world_id" =~ ^[0-9]+$ ]]; then
  echo "Error: target_world_id is not numeric: '$target_world_id'" >&2
  exit 1
fi
for wid in "${source_world_ids_uniq[@]}"; do
  if ! [[ "$wid" =~ ^[0-9]+$ ]]; then
    echo "Error: source_world_id is not numeric: '$wid'" >&2
    exit 1
  fi
done

export PGHOST="$GAME_HOST"
export PGPORT="$GAME_PORT"
export PGUSER="$GAME_USER"
export PGPASSWORD="${GAME_PASS:-}"

echo "== merge_update_guild_race_data (PostgreSQL) =="
echo "INI             : $INI_PATH"
echo "GameDB Host     : $GAME_HOST:$GAME_PORT"
echo "GameDB Name     : $GAME_DB"
echo "target_world_id : $target_world_id"
echo "source_world_ids: ${source_world_ids_uniq[*]}"
echo

if ! check_gamedb_connection; then
  echo "Error: GameDB connection check failed." >&2
  exit 1
fi

########################################
# 1) Normalize（只做一次）
########################################
echo "Normalizing guild_race_data JSON structure ..."

psql -d "$GAME_DB" -v ON_ERROR_STOP=1 -X -t -A <<'SQL'
BEGIN;

WITH u AS (
  UPDATE guild_race_data AS grd
  SET fightrecordata =
    jsonb_set(
      COALESCE(grd.fightrecordata, '{}'::jsonb),
      '{fightrecords}',
      '{}'::jsonb,
      true
    )
  WHERE grd.fightrecordata IS NULL
     OR NOT (grd.fightrecordata ? 'fightrecords')
     OR (grd.fightrecordata -> 'fightrecords') IS NULL
     OR jsonb_typeof(grd.fightrecordata -> 'fightrecords') <> 'object'
  RETURNING 1
)
SELECT 'normalize fightrecordata rows: ' || count(*) FROM u;

WITH u AS (
  UPDATE guild_race_data AS grd
  SET defendrecordata =
    jsonb_set(
      COALESCE(grd.defendrecordata, '{}'::jsonb),
      '{defendrecords}',
      '{}'::jsonb,
      true
    )
  WHERE grd.defendrecordata IS NULL
     OR NOT (grd.defendrecordata ? 'defendrecords')
     OR (grd.defendrecordata -> 'defendrecords') IS NULL
     OR jsonb_typeof(grd.defendrecordata -> 'defendrecords') <> 'object'
  RETURNING 1
)
SELECT 'normalize defendrecordata rows: ' || count(*) FROM u;

COMMIT;
SQL

########################################
# 2) 逐 source_world_id 更新（只命中才更新）
########################################
for source_world_id in "${source_world_ids_uniq[@]}"; do
  echo "Updating guild_race_data: source_world_id=${source_world_id} -> target_world_id=${target_world_id}"

  psql -d "$GAME_DB" -v ON_ERROR_STOP=1 -X -t -A \
    -v source_world_id="$source_world_id" \
    -v target_world_id="$target_world_id" <<'SQL'
BEGIN;

-- fightrecordata：只在 JSON 內命中 source_world_id 時更新
WITH u AS (
  UPDATE guild_race_data AS grd
  SET fightrecordata =
    jsonb_set(
      grd.fightrecordata,
      '{fightrecords}',
      COALESCE(
        (
          SELECT jsonb_object_agg(e.key, v2)
          FROM jsonb_each(grd.fightrecordata -> 'fightrecords') AS e(key, value)
          CROSS JOIN LATERAL (
            SELECT CASE
              WHEN e.value ->> 'challengerworldID' = :'source_world_id' THEN
                jsonb_set(e.value, '{challengerworldID}', to_jsonb((:'target_world_id')::text), true)
              ELSE e.value
            END AS v1
          ) s1
          CROSS JOIN LATERAL (
            SELECT CASE
              WHEN s1.v1 ->> 'targetworldID' = :'source_world_id' THEN
                jsonb_set(s1.v1, '{targetworldID}', to_jsonb((:'target_world_id')::text), true)
              ELSE s1.v1
            END AS v2
          ) s2
        ),
        '{}'::jsonb
      ),
      true
    )
  WHERE EXISTS (
    SELECT 1
    FROM jsonb_each(grd.fightrecordata -> 'fightrecords') AS e(key, value)
    WHERE e.value ->> 'challengerworldID' = :'source_world_id'
       OR e.value ->> 'targetworldID'     = :'source_world_id'
  )
  RETURNING 1
)
SELECT 'fightrecordata update rows: ' || count(*) FROM u;

-- defendrecordata：只在 JSON 內命中 source_world_id 時更新
WITH u AS (
  UPDATE guild_race_data AS grd
  SET defendrecordata =
    jsonb_set(
      grd.defendrecordata,
      '{defendrecords}',
      COALESCE(
        (
          SELECT jsonb_object_agg(e.key, v2)
          FROM jsonb_each(grd.defendrecordata -> 'defendrecords') AS e(key, value)
          CROSS JOIN LATERAL (
            SELECT CASE
              WHEN e.value ->> 'challengerworldID' = :'source_world_id' THEN
                jsonb_set(e.value, '{challengerworldID}', to_jsonb((:'target_world_id')::text), true)
              ELSE e.value
            END AS v1
          ) s1
          CROSS JOIN LATERAL (
            SELECT CASE
              WHEN s1.v1 ->> 'targetworldID' = :'source_world_id' THEN
                jsonb_set(s1.v1, '{targetworldID}', to_jsonb((:'target_world_id')::text), true)
              ELSE s1.v1
            END AS v2
          ) s2
        ),
        '{}'::jsonb
      ),
      true
    )
  WHERE EXISTS (
    SELECT 1
    FROM jsonb_each(grd.defendrecordata -> 'defendrecords') AS e(key, value)
    WHERE e.value ->> 'challengerworldID' = :'source_world_id'
       OR e.value ->> 'targetworldID'     = :'source_world_id'
  )
  RETURNING 1
)
SELECT 'defendrecordata update rows: ' || count(*) FROM u;

SELECT 'source_world_id=' || :'source_world_id' || ' -> target_world_id=' || :'target_world_id' || ' done';

COMMIT;
SQL

done

echo "All updates done."

