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

###############################################################################
# 腳本名稱：run_merge_n1_echo
#
# 用法：
#   run_merge_n1_echo <ENVIRONMENT> <FILE_NAME> [MODULE] [MODULE_ARGS...] [SetID...]
#
# 參數說明：
#   $1: ENVIRONMENT
#       - test / live
#
#   $2: FILE_NAME
#       - 對應 $HOME/bin/merge_n1/<ENVIRONMENT>/<FILE_NAME>
#
#   $3: MODULE (可省略；預設 exec_merge)
#
#   $4..: MODULE_ARGS 與 SetID filters
#
# SetID filters（可複數）：
#   - 格式：S11 / S21 / S31 ...
#   - 預設不加：針對 FILE_NAME 內的所有 world_id_lists 都全部執行
#   - 若有加 SetID：則僅針對指定 SetID 的 world_id_lists 執行
#
# ---------------------------------------------------------------------------
# 單一基礎功能 (Single / Base Modules)
# ---------------------------------------------------------------------------
#   generate
#   reward_before_merge
#   dbcheck
#   prebackup
#   restore_prebackup
#   merge
#   logcheck
#   waitdone
#   update_guild_race_data
#   postbackup
#   check
#   merge_rollback_partial_worlds
#   update_db_setup
#   move_old_server_directory
#   remove_source_wids_on_hosts
#   removebackup
#   removebackup_wb
#   removebackup_wob
#
# ---------------------------------------------------------------------------
# 群組功能 (Group Modules)
# ---------------------------------------------------------------------------
#   exec_merge =
#       generate
#       + dbcheck
#       + prebackup
#       + merge
#       + logcheck
#       + waitdone
#       + update_guild_race_data
#       + postbackup
#       + check
#
#   before_merge =
#       generate
#       + reward_before_merge
#
#   after_merge =
#       update_db_setup
#       + move_old_server_directory
#       + remove_source_wids_on_hosts
#
#   end_merge =
#       removebackup
#
#   re_run_pre_merge =
#       removebackup_wob post
#       + restore_prebackup
#       + merge_rollback_partial_worlds
#
#   re_run_exec_merge =
#       removebackup_wob post
#       + restore_prebackup
#       + merge_rollback_partial_worlds
#       + merge
#       + logcheck
#       + waitdone
#       + update_guild_race_data
#       + postbackup
#       + check
#
#   re_run_exec_merge_wo_restore =
#       merge
#       + logcheck
#       + waitdone
#       + update_guild_race_data
#       + postbackup
#       + check
###############################################################################

if [ "$#" -lt 2 ]; then
    echo "Usage: $0 <ENVIRONMENT: test|live> <FILE_NAME> [MODULE] [MODULE_ARGS...] [SetID filters...]" >&2
    exit 1
fi

ENVIRONMENT="$1"
FILE_NAME="$2"
MODULE="${3:-exec_merge}"

case "$ENVIRONMENT" in
    test|live) ;;
    *)
        echo "Error: ENVIRONMENT must be 'test' or 'live', got '$ENVIRONMENT'." >&2
        exit 1
        ;;
esac

INPUT_FILE="$HOME/bin/merge_n1/${ENVIRONMENT}/${FILE_NAME}"
if [ ! -f "$INPUT_FILE" ]; then
    echo "Error: input file not found: $INPUT_FILE" >&2
    exit 1
fi
if [ ! -s "$INPUT_FILE" ]; then
    echo "Error: input file is empty: $INPUT_FILE" >&2
    exit 1
fi

START_TS=$(date +%s)
START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
echo "== run_merge_n1_echo start at ${START_TIME} (ENV=${ENVIRONMENT}, FILE_NAME=${FILE_NAME}, MODULE=${MODULE}) =="

declare -A list_worlds
declare -A list_setid
declare -A set_lists
declare -A set_first_list
declare -a all_lists
declare -a ordered_set_ids

declare -a REM_ARGS=()
if [ "$#" -ge 4 ]; then
    shift 3
    REM_ARGS=( "$@" )
fi

REMOVE_WHICH=""
declare -a SET_FILTERS=()

is_set_filter() { [[ "$1" =~ ^[sS][0-9]{2}$ ]]; }
normalize_set_filter() { local x="$1"; x="${x#S}"; x="${x#s}"; printf '%s' "$x"; }

if [[ "$MODULE" =~ ^removebackup($|_) ]]; then
    if [ "${#REM_ARGS[@]}" -ge 1 ] && ! is_set_filter "${REM_ARGS[0]}"; then
        case "${REM_ARGS[0]}" in
            pre|post)
                REMOVE_WHICH="${REM_ARGS[0]}"
                REM_ARGS=( "${REM_ARGS[@]:1}" )
                ;;
            *)
                echo "Error: removebackup* optional arg must be 'pre' or 'post' (or omitted)." >&2
                exit 1
                ;;
        esac
    fi
fi

if [ "${#REM_ARGS[@]}" -gt 0 ]; then
    declare -A SEEN_SID=()
    for a in "${REM_ARGS[@]}"; do
        if ! is_set_filter "$a"; then
            echo "Error: invalid SetID filter '${a}'. Expect format like S11 / S21 / S31." >&2
            exit 1
        fi
        sid="$(normalize_set_filter "$a")"
        if [[ -z "${SEEN_SID[$sid]+x}" ]]; then
            SEEN_SID["$sid"]=1
            SET_FILTERS+=( "$sid" )
        fi
    done
fi

LINE_NO=0
declare -A seen_setid=()

while IFS= read -r line || [ -n "$line" ]; do
    LINE_NO=$((LINE_NO + 1))

    line_trimmed="${line#"${line%%[![:space:]]*}"}"
    line_trimmed="${line_trimmed%"${line_trimmed##*[![:space:]]}"}"

    if [ -z "$line_trimmed" ] || [[ "$line_trimmed" =~ ^# ]]; then
        continue
    fi

    read -r -a WORLDS <<< "$line_trimmed"
    [ "${#WORLDS[@]}" -lt 1 ] && continue

    LINE_SET_ID=""
    for wid in "${WORLDS[@]}"; do
        wid_set_id=$(( wid / 100 ))
        if [ -z "$LINE_SET_ID" ]; then
            LINE_SET_ID="$wid_set_id"
        fi
    done

    LID="L${LINE_NO}"
    list_worlds["$LID"]="$line_trimmed"
    list_setid["$LID"]="$LINE_SET_ID"
    all_lists+=( "$LID" )

    if [[ -z "${set_lists[$LINE_SET_ID]+x}" ]]; then
        set_lists["$LINE_SET_ID"]="$LID"
        set_first_list["$LINE_SET_ID"]="$LID"
    else
        set_lists["$LINE_SET_ID"]+=" $LID"
    fi

    if [[ -z "${seen_setid[$LINE_SET_ID]+x}" ]]; then
        seen_setid["$LINE_SET_ID"]=1
        ordered_set_ids+=( "$LINE_SET_ID" )
    fi
done < "$INPUT_FILE"

declare -a ACTIVE_LISTS=()
declare -A ACTIVE_SET_LISTS=()
declare -A ACTIVE_SET_FIRST=()
declare -a ACTIVE_ORDERED_SET_IDS=()
declare -A active_seen_setid=()

if [ "${#SET_FILTERS[@]}" -eq 0 ]; then
    ACTIVE_LISTS=( "${all_lists[@]}" )
    for sid in "${ordered_set_ids[@]}"; do
        ACTIVE_SET_LISTS["$sid"]="${set_lists[$sid]}"
        ACTIVE_SET_FIRST["$sid"]="${set_first_list[$sid]}"
        ACTIVE_ORDERED_SET_IDS+=( "$sid" )
    done
else
    declare -A want_sid=()
    for sid in "${SET_FILTERS[@]}"; do want_sid["$sid"]=1; done

    for lid in "${all_lists[@]}"; do
        sid="${list_setid[$lid]}"
        if [[ -n "${want_sid[$sid]+x}" ]]; then
            ACTIVE_LISTS+=( "$lid" )
            if [[ -z "${ACTIVE_SET_LISTS[$sid]+x}" ]]; then
                ACTIVE_SET_LISTS["$sid"]="$lid"
                ACTIVE_SET_FIRST["$sid"]="$lid"
            else
                ACTIVE_SET_LISTS["$sid"]+=" $lid"
            fi
            if [[ -z "${active_seen_setid[$sid]+x}" ]]; then
                active_seen_setid["$sid"]=1
                ACTIVE_ORDERED_SET_IDS+=( "$sid" )
            fi
        fi
    done
fi

FIRST_LID_GLOBAL="${ACTIVE_LISTS[0]}"
FIRST_SETID_GLOBAL="${list_setid[$FIRST_LID_GLOBAL]}"

get_area_machine_and_generator() {
    local env="$1"
    local sid="$2"
    local area=""
    local machine=""
    local generator=""

    if (( sid >= 10 && sid < 20 )); then
        area="asia"
    elif (( sid >= 20 && sid < 30 )); then
        area="us"
    elif (( sid >= 30 && sid < 40 )); then
        area="eu"
    else
        return 1
    fi

    if [ "$env" = "live" ]; then
        machine="MS${sid}"
        generator="generate_merge_preparation"
    else
        case "$area" in
            asia) machine="MERGE_ASIA" ;;
            us)   machine="MERGE_US" ;;
            eu)   machine="MERGE_EU" ;;
        esac
        generator="generate_merge_preparation_test"
    fi

    printf '%s %s %s\n' "$area" "$machine" "$generator"
}

run_generate() {
    echo ">>> MODULE: generate"
    for set_id in "${ACTIVE_ORDERED_SET_IDS[@]}"; do
        read AREA MACHINE GENERATOR < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        read -r -a LIDS <<< "${ACTIVE_SET_LISTS[$set_id]}"

        echo "==== SET_ID ${set_id} / AREA=${AREA} / MACHINE=${MACHINE} / GEN=${GENERATOR} ===="
        for lid in "${LIDS[@]}"; do
            WORLD_ID_LISTS="${list_worlds[$lid]}"
            echo "ssh \"$MACHINE\" \"\$HOME/bin/${GENERATOR} ${DIRECTORY_NAME} ${WORLD_ID_LISTS}\""
        done
    done
    echo
}

run_db_connect_verify() {
    echo ">>> MODULE: dbcheck"
    for set_id in "${ACTIVE_ORDERED_SET_IDS[@]}"; do
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        read -r -a LIDS <<< "${ACTIVE_SET_LISTS[$set_id]}"

        for lid in "${LIDS[@]}"; do
            WORLD_ID_LISTS="${list_worlds[$lid]}"
            WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
            REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
            REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"
            echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_connect_verify \\\"${REMOTE_MERGE_INI}\\\"\""
        done
    done
    echo
}

run_pre_backup() {
    echo ">>> MODULE: prebackup"

    read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$FIRST_SETID_GLOBAL")
    DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
    WORLD_ID_LISTS_FIRST_GLOBAL="${list_worlds[$FIRST_LID_GLOBAL]}"
    WORLD_ID_LISTS_STR_FIRST_GLOBAL=${WORLD_ID_LISTS_FIRST_GLOBAL// /_}
    REMOTE_BASE_DIR_FIRST_GLOBAL="\$HOME/servers${FIRST_SETID_GLOBAL}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_GLOBAL}"
    REMOTE_MERGE_INI_FIRST_GLOBAL="${REMOTE_BASE_DIR_FIRST_GLOBAL}/merge_setup.ini"

    echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI_FIRST_GLOBAL}\\\" _${FILE_NAME}_Pre AccountDB\""

    for set_id in "${ACTIVE_ORDERED_SET_IDS[@]}"; do
        FIRST_LID="${ACTIVE_SET_FIRST[$set_id]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS_FIRST_SET="${list_worlds[$FIRST_LID]}"
        WORLD_ID_LISTS_STR_FIRST_SET=${WORLD_ID_LISTS_FIRST_SET// /_}
        REMOTE_BASE_DIR_FIRST_SET="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_SET}"
        REMOTE_MERGE_INI_FIRST_SET="${REMOTE_BASE_DIR_FIRST_SET}/merge_setup.ini"

        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI_FIRST_SET}\\\" _${FILE_NAME}_Pre GameDB\""
    done

    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"

        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI}\\\" _${FILE_NAME}_Pre WorldDB\""
    done
    echo
}

run_restore_prebackup() {
    echo ">>> MODULE: restore_prebackup"

    read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$FIRST_SETID_GLOBAL")
    DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
    WORLD_ID_LISTS_FIRST_GLOBAL="${list_worlds[$FIRST_LID_GLOBAL]}"
    WORLD_ID_LISTS_STR_FIRST_GLOBAL=${WORLD_ID_LISTS_FIRST_GLOBAL// /_}
    REMOTE_BASE_DIR_FIRST_GLOBAL="\$HOME/servers${FIRST_SETID_GLOBAL}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_GLOBAL}"
    REMOTE_MERGE_INI_FIRST_GLOBAL="${REMOTE_BASE_DIR_FIRST_GLOBAL}/merge_setup.ini"

    echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_restore \\\"${REMOTE_MERGE_INI_FIRST_GLOBAL}\\\" _${FILE_NAME}_Pre AccountDB\""

    for set_id in "${ACTIVE_ORDERED_SET_IDS[@]}"; do
        FIRST_LID="${ACTIVE_SET_FIRST[$set_id]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS_FIRST_SET="${list_worlds[$FIRST_LID]}"
        WORLD_ID_LISTS_STR_FIRST_SET=${WORLD_ID_LISTS_FIRST_SET// /_}
        REMOTE_BASE_DIR_FIRST_SET="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_SET}"
        REMOTE_MERGE_INI_FIRST_SET="${REMOTE_BASE_DIR_FIRST_SET}/merge_setup.ini"

        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_restore \\\"${REMOTE_MERGE_INI_FIRST_SET}\\\" _${FILE_NAME}_Pre GameDB\""
    done

    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"

        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_restore \\\"${REMOTE_MERGE_INI}\\\" _${FILE_NAME}_Pre WorldDB\""
    done
    echo
}

run_merge_rollback_partial_worlds() {
    echo ">>> MODULE: merge_rollback_partial_worlds"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"

        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_rollback_partial_worlds \\\"${REMOTE_MERGE_INI}\\\" \\\"${FILE_NAME}_Pre\\\"\""
    done
    echo
}

run_merge_exec() {
    echo ">>> MODULE: merge"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        echo "ssh \"$MACHINE\" \"cd ${REMOTE_BASE_DIR}; nohup ./merge_exec &\""
    done
    echo
}

run_log_check() {
    echo ">>> MODULE: logcheck"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        echo "ssh \"$MACHINE\" \"cd ${REMOTE_BASE_DIR}; grep -E ',WolrdDB|,WorldDB|,GameDB|,AccountDB|,Done| autosend_info| redenvelope_info' Test.log* || echo 'No match in Test.log*'\""
    done
    echo
}

run_wait_done() {
    echo ">>> MODULE: waitdone"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        echo "ssh \"$MACHINE\" \"cd ${REMOTE_BASE_DIR}; grep -q ',Done' Test.log* 2>/dev/null\""
    done
    echo
}

run_update_guild_race_data() {
    echo ">>> MODULE: update_guild_race_data"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"
        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_update_guild_race_data \\\"${REMOTE_MERGE_INI}\\\"\""
    done
    echo
}

run_post_backup() {
    echo ">>> MODULE: postbackup"

    read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$FIRST_SETID_GLOBAL")
    DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
    WORLD_ID_LISTS_FIRST_GLOBAL="${list_worlds[$FIRST_LID_GLOBAL]}"
    WORLD_ID_LISTS_STR_FIRST_GLOBAL=${WORLD_ID_LISTS_FIRST_GLOBAL// /_}
    REMOTE_BASE_DIR_FIRST_GLOBAL="\$HOME/servers${FIRST_SETID_GLOBAL}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_GLOBAL}"
    REMOTE_MERGE_INI_FIRST_GLOBAL="${REMOTE_BASE_DIR_FIRST_GLOBAL}/merge_setup.ini"
    echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI_FIRST_GLOBAL}\\\" _${FILE_NAME}_Post AccountDB\""

    for set_id in "${ACTIVE_ORDERED_SET_IDS[@]}"; do
        FIRST_LID="${ACTIVE_SET_FIRST[$set_id]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS_FIRST_SET="${list_worlds[$FIRST_LID]}"
        WORLD_ID_LISTS_STR_FIRST_SET=${WORLD_ID_LISTS_FIRST_SET// /_}
        REMOTE_BASE_DIR_FIRST_SET="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR_FIRST_SET}"
        REMOTE_MERGE_INI_FIRST_SET="${REMOTE_BASE_DIR_FIRST_SET}/merge_setup.ini"
        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI_FIRST_SET}\\\" _${FILE_NAME}_Post GameDB\""
    done

    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"
        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_db_backup \\\"${REMOTE_MERGE_INI}\\\" _${FILE_NAME}_Post WorldDB\""
    done
    echo
}

run_check_diff() {
    echo ">>> MODULE: check"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA MACHINE _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        WORLD_ID_LISTS_STR=${WORLD_ID_LISTS// /_}
        REMOTE_BASE_DIR="\$HOME/servers${set_id}/${DIRECTORY_NAME}/${WORLD_ID_LISTS_STR}"
        REMOTE_MERGE_INI="${REMOTE_BASE_DIR}/merge_setup.ini"
        echo "ssh \"$MACHINE\" \"\$HOME/bin/merge_check \\\"${REMOTE_MERGE_INI}\\\" _${FILE_NAME}_Pre _${FILE_NAME}_Post ${ENVIRONMENT}\""
    done
    echo
}

run_update_db_setup() {
    echo ">>> MODULE: update_db_setup"
    if [ "$ENVIRONMENT" != "live" ]; then
        echo "# (skip) update_db_setup only for live"
        echo
        return
    fi
    for lid in "${ACTIVE_LISTS[@]}"; do
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        echo "\$HOME/bin/update_db_setup_for_merge ${WORLD_ID_LISTS}"
    done
    echo
}

run_move_old_server_directory() {
    echo ">>> MODULE: move_old_server_directory"
    for lid in "${ACTIVE_LISTS[@]}"; do
        set_id="${list_setid[$lid]}"
        read AREA _ _ < <(get_area_machine_and_generator "$ENVIRONMENT" "$set_id")
        DIRECTORY_NAME="merge_${AREA}_${FILE_NAME}_${ENVIRONMENT}"
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        echo "\$HOME/bin/move_source_wids_directory_after_merge ${ENVIRONMENT} ${DIRECTORY_NAME} ${WORLD_ID_LISTS}"
    done
    echo
}

run_remove_source_wids_on_hosts() {
    echo ">>> MODULE: remove_source_wids_on_hosts"
    if [ "$ENVIRONMENT" != "live" ]; then
        echo "# (skip) remove_source_wids_on_hosts only for live"
        echo
        return
    fi
    echo "cp -arf \"\$HOME/bin/hosts\" \"\$HOME/bin/hosts.old\""
    for lid in "${ACTIVE_LISTS[@]}"; do
        WORLD_ID_LISTS="${list_worlds[$lid]}"
        echo "\$HOME/bin/remove_source_wids_on_hosts_after_merge ${WORLD_ID_LISTS}"
    done
    echo
}

run_remove_backup_core() {
    local which="${1-}"
    local backup_flag="${2-}"

    echo ">>> MODULE: removebackup"

    declare -a patterns=()
    case "$which" in
        pre)  patterns=( "_${FILE_NAME}_Pre" ) ;;
        post) patterns=( "_${FILE_NAME}_Post" ) ;;
        "")   patterns=( "_${FILE_NAME}_Pre" "_${FILE_NAME}_Post" ) ;;
        *)
            echo "Error: removebackup which must be 'pre' or 'post' (or omitted)." >&2
            exit 1
            ;;
    esac

    if [ "$ENVIRONMENT" = "test" ]; then
        for m in MERGE_COMMON MERGE_ASIA MERGE_US MERGE_EU; do
            echo "# [removebackup] test env on ${m} for FILE_NAME=${FILE_NAME}"
            for p in "${patterns[@]}"; do
                if [ -n "$backup_flag" ]; then
                    echo "ssh \"$m\" \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p} ${backup_flag}\""
                else
                    echo "ssh \"$m\" \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p}\""
                fi
            done
        done
        echo
        return
    fi

    # 你指定的正確寫法（原樣保留）
    if [ "${#SET_FILTERS[@]}" -eq 0 ]; then
        echo "# [removebackup] live env via sendscript alldb for FILE_NAME=${FILE_NAME}"
        for p in "${patterns[@]}"; do
            if [ -n "$backup_flag" ]; then
                echo "sendscript alldb <<< \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p} ${backup_flag}\""
            else
                echo "sendscript alldb <<< \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p}\""
            fi
        done
    else
        for sid in "${SET_FILTERS[@]}"; do
            m="set${sid}"
            echo "# [removebackup] live env on ${m} for FILE_NAME=${FILE_NAME}"
            for p in "${patterns[@]}"; do
                if [ -n "$backup_flag" ]; then
                    echo "sendscript $m <<< \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p} ${backup_flag}\""
                else
                    echo "sendscript $m <<< \"\$HOME/bin/drop_database_for_current_machine_by_pattern postfix ${p}\""
                fi
            done
        done
    fi
    echo
}

run_remove_backup() { run_remove_backup_core "$REMOVE_WHICH" ""; }
run_remove_backup_wb() { run_remove_backup_core "$REMOVE_WHICH" "1"; }
run_remove_backup_wob() { run_remove_backup_core "$REMOVE_WHICH" "0"; }

case "$MODULE" in
    exec_merge)
        run_generate
        run_db_connect_verify
        run_pre_backup
        run_merge_exec
        run_log_check
        run_wait_done
        run_update_guild_race_data
        run_post_backup
        run_check_diff
        ;;
    before_merge)
        run_generate
        echo ">>> MODULE: reward_before_merge"
        echo "# \$HOME/bin/send_fastcgi_all_once_n1_by_world_reward_merge ${ENVIRONMENT} <WORLD_ID_LISTS...>"
        echo
        ;;
    after_merge)
        run_update_db_setup
        run_move_old_server_directory
        run_remove_source_wids_on_hosts
        ;;
    end_merge)
        run_remove_backup
        ;;
    re_run_pre_merge)
        REMOVE_WHICH="post"
        run_remove_backup_wob
        run_restore_prebackup
        run_merge_rollback_partial_worlds
        ;;
    re_run_exec_merge)
        REMOVE_WHICH="post"
        run_remove_backup_wob
        run_restore_prebackup
        run_merge_rollback_partial_worlds
        run_merge_exec
        run_log_check
        run_wait_done
        run_update_guild_race_data
        run_post_backup
        run_check_diff
        ;;
    re_run_exec_merge_wo_restore)
        run_merge_exec
        run_log_check
        run_wait_done
        run_update_guild_race_data
        run_post_backup
        run_check_diff
        ;;
    generate) run_generate ;;
    dbcheck) run_db_connect_verify ;;
    prebackup) run_pre_backup ;;
    restore_prebackup) run_restore_prebackup ;;
    merge_rollback_partial_worlds) run_merge_rollback_partial_worlds ;;
    merge) run_merge_exec ;;
    logcheck) run_log_check ;;
    waitdone) run_wait_done ;;
    update_guild_race_data) run_update_guild_race_data ;;
    postbackup) run_post_backup ;;
    check) run_check_diff ;;
    update_db_setup) run_update_db_setup ;;
    move_old_server_directory) run_move_old_server_directory ;;
    remove_source_wids_on_hosts) run_remove_source_wids_on_hosts ;;
    removebackup) run_remove_backup ;;
    removebackup_wb) run_remove_backup_wb ;;
    removebackup_wob) run_remove_backup_wob ;;
    *)
        echo "Error: unknown MODULE '${MODULE}'." >&2
        exit 1
        ;;
esac

END_TS=$(date +%s)
END_TIME=$(date '+%Y-%m-%d %H:%M:%S')
ELAPSED=$((END_TS - START_TS))
ELAPSED_H=$((ELAPSED / 3600))
ELAPSED_M=$(((ELAPSED % 3600) / 60))
ELAPSED_S=$((ELAPSED % 60))

echo "== run_merge_n1_echo finished (MODULE=${MODULE}) =="
echo "Start time : ${START_TIME}"
echo "End time   : ${END_TIME}"
printf 'Elapsed    : %02d 小時 %02d 分 %02d 秒\n' "$ELAPSED_H" "$ELAPSED_M" "$ELAPSED_S"
echo "ENV=${ENVIRONMENT}, FILE_NAME=${FILE_NAME}"

