#!/usr/bin/env bash

# 載入 DB 設定
# 用法：load_merge_db_setup /path/to/merge_setup.ini
load_merge_db_setup() {
    local SETUP_FILE="$1"

    if [[ -z "$SETUP_FILE" ]]; then
        echo "load_merge_db_setup: 需要指定 config 檔路徑" >&2
        return 1
    fi

    if [[ ! -f "$SETUP_FILE" ]]; then
        echo "load_merge_db_setup: 找不到檔案: $SETUP_FILE" >&2
        return 1
    fi

    # 清掉舊資料（避免重複載入時殘留）
    unset account game world_ids world_order
    declare -gA account
    declare -gA game
    declare -gA world_ids
    declare -ga world_order

    local key value wid k
    # current 一開始給空陣列，避免在 set -u 下 referencing 未宣告的陣列
    local -A current=()

    while IFS='=' read -r key value; do
        # 去掉前後空白（如果有）
        key="${key%%[[:space:]]*}"
        value="${value##[[:space:]]}"

        # 空行或註解跳過
        [[ -z "$key" ]] && continue
        [[ "$key" =~ ^# ]] && continue

        case "$key" in
            # -------- Account 區段 --------
            AccountDBIP|AccountDBName|AccountDBUser|AccountDBPW)
                account["$key"]="$value"
                ;;

            # -------- Game 區段 --------
            GameDBIP|GameDB|GameDBUser|GameDBPassword)
                game["$key"]="$value"
                ;;

            # -------- World 區段 --------
            WorldID)
                # 如果 current 裡已經有上一組 WorldID，就把上一組寫出去
                if [[ -n "${current[WorldID]-}" ]]; then
                    wid="${current[WorldID]}"

                    # 宣告全域 associative array：world_<WorldID>
                    eval "declare -gA world_${wid}"
                    for k in "${!current[@]}"; do
                        # world_1001[WorldDBIP]='192.168.1.3'
                        eval "world_${wid}[\$k]='${current[$k]}'"
                    done
                    world_ids["$wid"]=1
                    world_order+=("$wid")
                fi

                # 開新一組 world
                current=()               # 清空 current 陣列
                current["WorldID"]="$value"
                ;;

            WorldDBIP|WorldDBName|WorldDBUser|WorldDBPassword)
                current["$key"]="$value"
                ;;
        esac
    done < "$SETUP_FILE"

    # 檔案結尾，把最後一組 world 寫入
    if [[ -n "${current[WorldID]-}" ]]; then
        wid="${current[WorldID]}"

        eval "declare -gA world_${wid}"
        for k in "${!current[@]}"; do
            eval "world_${wid}[\$k]='${current[$k]}'"
        done
        world_ids["$wid"]=1
        world_order+=("$wid")
    fi
}

# 取 World DB 的欄位值
# 用法：get_worlddb_value <WorldID> <Key>
get_worlddb_value() {
    local wid="$1"
    local key="$2"

    if [[ -z "${wid-}" || -z "${key-}" ]]; then
        return 1
    fi

    # 注意這裡多了一個 - ：[${key}]- 讓「不存在的元素」展開成空字串，而不是 unbound
    eval "printf '%s' \"\${world_${wid}[${key}]-}\""
}

# 取 Account DB 的欄位值
# 用法：get_accountdb_value <Key>
get_accountdb_value() {
    local key="$1"

    if [[ -z "${key-}" ]]; then
        return 1
    fi

    printf '%s' "${account[$key]-}"
}

# 取 Game DB 的欄位值
# 用法：get_gamedb_value <Key>
get_gamedb_value() {
    local key="$1"

    if [[ -z "${key-}" ]]; then
        return 1
    fi

    printf '%s' "${game[$key]-}"
}

########################################
# 撈取 Setup File 內所有 DB Name
########################################

# 回傳值：將所有 DB 名稱放進全域 array：dbs_array
# 排序順序：固定順序 Account → Game → World(依 world_order)
get_all_db_names() {
    unset dbs_array
    declare -ga dbs_array=()

    # 1. Account
    local acc_db
    acc_db=$(get_accountdb_value "AccountDBName")
    if [[ -n "${acc_db-}" ]]; then
        dbs_array+=("$acc_db")
    fi

    # 2. Game
    local game_db
    game_db=$(get_gamedb_value "GameDB")
    if [[ -n "${game_db-}" ]]; then
        dbs_array+=("$game_db")
    fi

    # 3. World（依 setup 順序）
    local wid world_db
    for wid in "${world_order[@]}"; do
        world_db=$(get_worlddb_value "$wid" "WorldDBName")
        if [[ -n "${world_db-}" ]]; then
            dbs_array+=("$world_db")
        fi
    done
}

# 將 World ID Lists 轉成 DB IN 語法可用的逗點分隔
# 用法 join_by_comma ${arr[@]}"
join_by_comma() {
    #local arr=("$@")
    #IFS=',' read -r out <<< "${arr[*]}"
    #printf '%s' "$out"
    local IFS=','
    printf '%s' "$*"
}

# 回傳 array 的元素數量
# 用法：
#   array_length arr[@]
#   array_length "${sorted_world_ids[@]}"
#
# 注意：要傳 arr[@] 才能正確取得整個陣列
array_length() {
    local arr=("$@")
    printf '%d' "${#arr[@]}"
}

########################################
# DB 連線檢查相關函式（PostgreSQL 16）
########################################

# 共用：檢查 PostgreSQL 連線是否可用
# 參數：HOST DB_NAME USER PASS [PORT]
# 回傳碼：
#   0 = OK
#   3 = TCP / 網路層連不到主機或服務
#   4 = 主機可達，但 DB/認證錯誤
#   2 = 基本參數不完整
_db_pg_ping() {
    local host="${1-}"
    local db="${2-}"
    local user="${3-}"
    local pass="${4-}"
    local port="${5-}"

    if [[ -z "$host" || -z "$db" || -z "$user" ]]; then
        echo "[ERROR] host/db/user 未設定完整 (host='$host', db='$db', user='$user')" >&2
        return 2
    fi

    # 預設 port 5432
    if [[ -z "$port" ]]; then
        port=5432
    fi

    # 設一個合理的連線 timeout，避免 IP 錯誤時卡住太久
    local connect_timeout="${PGCONNECT_TIMEOUT:-3}"

    local out rc
    out=$(
        PGPASSWORD="$pass" PGCONNECT_TIMEOUT="$connect_timeout" \
        psql -h "$host" -p "$port" -U "$user" -d "$db" \
             -c 'SELECT 1;' -tA \
             2>&1 >/dev/null
    )
    rc=$?

    if (( rc == 0 )); then
        # 一切正常
        return 0
    fi

    # 判斷「連不到主機 / 服務」的典型錯誤字串
    if [[ "$out" == *"could not connect to server"* ]]    || \
       [[ "$out" == *"No route to host"* ]]               || \
       [[ "$out" == *"Connection refused"* ]]             || \
       [[ "$out" == *"Connection timed out"* ]]           || \
       [[ "$out" == *"Name or service not known"* ]]; then
        echo "[ERROR] 無法連線到 ${host}:${port} (網路 / 服務不可達)：$out" >&2
        return 3
    fi

    # 其餘當作「主機可達，但 DB / 認證錯誤」
    echo "[ERROR] 已連到 ${host}:${port}，但 DB/認證失敗：$out" >&2
    return 4
}

# 檢查 Account DB 連線
# 回傳值：0 = OK, 1 = 失敗
check_accountdb_connection() {
    local host db user pass port

    host=$(get_accountdb_value "AccountDBIP")
    db=$(get_accountdb_value "AccountDBName")
    user=$(get_accountdb_value "AccountDBUser")
    pass=$(get_accountdb_value "AccountDBPW")
    # 若將來在 config 加 AccountDBPort，可以這樣讀；目前沒有就會是空字串
    port=$(get_accountdb_value "AccountDBPort")

    _db_pg_ping "$host" "$db" "$user" "$pass" "$port"
}

# 檢查 Game DB 連線
# 回傳值：0 = OK, 1 = 失敗
check_gamedb_connection() {
    local host db user pass port

    host=$(get_gamedb_value "GameDBIP")
    # 你的設定裡是 GameDB=Game10，如果未來改成 GameDBName 也只要同步修正這裡
    db=$(get_gamedb_value "GameDB")
    user=$(get_gamedb_value "GameDBUser")
    pass=$(get_gamedb_value "GameDBPassword")
    port=$(get_gamedb_value "GameDBPort")

    _db_pg_ping "$host" "$db" "$user" "$pass" "$port"
}

# 檢查某一個 World DB 連線
# 用法：check_worlddb_connection <WorldID>
# 回傳值：0 = OK, 1 = 失敗
check_worlddb_connection() {
    local wid="$1"
    local host db user pass port

    if [[ -z "${wid-}" ]]; then
        return 2
    fi

    host=$(get_worlddb_value "$wid" "WorldDBIP")
    db=$(get_worlddb_value "$wid" "WorldDBName")
    user=$(get_worlddb_value "$wid" "WorldDBUser")
    pass=$(get_worlddb_value "$wid" "WorldDBPassword")
    port=$(get_worlddb_value "$wid" "WorldDBPort")

    _db_pg_ping "$host" "$db" "$user" "$pass" "$port"
}

