#!/usr/bin/env bash
# compare_platforms_for_clientpatch — 比對 client patch 兩版本的平台差異
#
# 用法:
#   compare_platforms_for_clientpatch [--action <name>] [--a-label <str>] [--b-label <str>] [--thread-tag <tag>] [--no-notify] [--no-exclude] <A_old> <B_new>
#
# --action 可指定場景，會自動推導 a-label / b-label / thread-tag / title / exclude：
#   "test_update"  A_LABEL 優先讀 $COMPARE_PLATFORMS_STATE_DIR/test_update.last（由 TestCtrl 寫入），
#                  否則 fallback heuristic（掃 $HOME/patch/ 字典序倒數第二）；
#                  B_LABEL = $HOME/patch/ 字典序倒數第一；thread-tag=test_patch，套用 exclude
#   "live_sync"    A=$WORKING_DIRECTORY/www/${GAME_TYPE}-TEST_SYNCTOLIVE（複製到 /tmp/…_RESTORE 後依 setup.txt
#                  的 NFSExtension 批次改名），B=$WORKING_DIRECTORY/www/${GAME_TYPE}-TEST；
#                  label 用目錄名；thread-tag=client_sync；預設 --no-exclude（全比）；
#                  positional A、B 可省略，由 action 自動推導
#   (未設定)        維持 CLI 原行為，title="Client Patch"，套用 exclude
#
# --no-exclude  強制忽略 conf 的 COMPARE_PLATFORMS_EXCLUDE_PATHS（完整比對）。
#               顯式傳入會覆寫 action 的預設值。
#
# 差異三類（差異數量全部計入；差異大小只計 B 端與新版）：
#   A 獨有      — A 有 B 無；計入數量，**不計入**差異大小（舊版才有，新版不需下載）
#   B 獨有      — B 有 A 無；計入數量，計入差異大小 = sizeB
#   內容不同    — md5 不同；計入數量，計入差異大小 = sizeB（新版 size）
#
# 比對方法：md5 內容比對（完全遞迴；排除 EXCLUDE_PATHS 指定的子路徑）
#
# 通知：
#   預設：透過 GOOGLE_CHAT_WEBHOOK_URL 直接 curl（單獨訊息）
#   --thread-tag <tag>：透過 send_chatbot_text_only_by_thread_tag 發到同 thread
#   --no-notify：完全不發
#
# 輸出：
#   螢幕 stdout（呼叫者可 tee 接）+ www/download/ 下的 Log（URL 可存取）
#
# Exit code: 0 = 成功跑完（不論有無差異），非 0 = 錯誤

set -u

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONF_FILE="$SCRIPT_DIR/compare_platforms_for_clientpatch.conf"

# 先 source .gamerc 取得 WORKING_DIRECTORY / GOOGLE_CHAT_WEBHOOK_URL / GAME_TYPE / COUNTRY_CODE_DISPLAY
# （conf 內可能用到 $WORKING_DIRECTORY，所以順序要在 conf 之前）
set +u
[[ -f "$HOME/.gamerc" ]] && source "$HOME/.gamerc"
set -u

[[ -f "$CONF_FILE" ]] || { echo "❌ 設定檔不存在: $CONF_FILE" >&2; exit 1; }
source "$CONF_FILE"

# ── arg parsing（旗標可放任何位置；positional 依順序收集）──
ACTION=""
THREAD_TAG=""
DO_NOTIFY=1
A_LABEL=""
B_LABEL=""
NO_EXCLUDE=0
NO_EXCLUDE_EXPLICIT=0
_POSITIONAL=()
while (( $# > 0 )); do
    case "$1" in
        --action)      ACTION="$2"; shift 2 ;;
        --a-label)     A_LABEL="$2"; shift 2 ;;
        --b-label)     B_LABEL="$2"; shift 2 ;;
        --thread-tag)  THREAD_TAG="$2"; shift 2 ;;
        --no-notify)   DO_NOTIFY=0; shift ;;
        --no-exclude)  NO_EXCLUDE=1; NO_EXCLUDE_EXPLICIT=1; shift ;;
        --help|-h)
            sed -n '2,/^# Exit code/p' "$0" | sed 's/^# \{0,1\}//'
            exit 0
            ;;
        --)            shift; _POSITIONAL+=("$@"); break ;;
        --*)           echo "未知選項: $1" >&2; echo "使用 --help 查看用法" >&2; exit 1 ;;
        *)             _POSITIONAL+=("$1"); shift ;;
    esac
done
set -- "${_POSITIONAL[@]:-}"

# ── 取 positional（action 沒 set 時需要由呼叫端傳）──
A="${1:-}"
B="${2:-}"

usage() {
    echo "用法: $0 [--action <name>] [--a-label <str>] [--b-label <str>]"
    echo "       [--thread-tag <tag>] [--no-notify] [--no-exclude] <A_old> <B_new>"
    echo "  action=live_sync 時 <A_old> <B_new> 可省略，會由 action 推導"
    echo "  其他情境下，A、B 目錄下應各有 ${COMPARE_PLATFORMS_SUBDIRS[*]} 等子目錄"
    exit 1
}

# ── 清理：TMPDIR 一定刪；LIVE_SYNC_CLEANUP_PATH 有安全檢查 ──
LIVE_SYNC_CLEANUP_PATH=""
_cleanup() {
    [[ -n "${TMPDIR:-}" && -d "$TMPDIR" ]] && rm -rf "$TMPDIR"
    if [[ -n "$LIVE_SYNC_CLEANUP_PATH" ]]; then
        _EXPECTED="/tmp/${GAME_TYPE:-__UNSET__}-TEST_SYNCTOLIVE_RESTORE"
        if [[ "$LIVE_SYNC_CLEANUP_PATH" == "$_EXPECTED" && -d "$LIVE_SYNC_CLEANUP_PATH" ]]; then
            rm -rf "$LIVE_SYNC_CLEANUP_PATH"
        fi
    fi
}
trap _cleanup EXIT

TMPDIR=$(mktemp -d -t compare_platforms.XXXXXX)

START_TIME=$(date +%s)
START_STR=$(date -d "@$START_TIME" '+%Y-%m-%d %H:%M:%S %Z')

# Log 檔固定放 www/download/ 下以便透過 URL 存取
mkdir -p "$COMPARE_PLATFORMS_DETAIL_OUTPUT_DIR"
LOG_FILENAME="compare_platforms_$(date -d "@$START_TIME" '+%Y%m%d_%H%M%S').log"
LOGFILE="$COMPARE_PLATFORMS_DETAIL_OUTPUT_DIR/$LOG_FILENAME"
LOG_URL="${COMPARE_PLATFORMS_DETAIL_BASE_URL%/}/$LOG_FILENAME"

exec > >(tee "$LOGFILE") 2>&1

# ── 依 action 推導預設值（手動參數優先於 action 推導）──
ACTION_TITLE="手動比對（Client Patch）"
case "$ACTION" in
    "test_update")
        ACTION_TITLE="測試機更新（test_update）"
        [[ -z "$THREAD_TAG" ]] && THREAD_TAG="test_patch"

        # A_LABEL 優先級：CLI 參數 > 狀態檔 > heuristic
        # 狀態檔：記錄上次 TestCtrl 成功安裝的版本
        _STATE_FILE="${COMPARE_PLATFORMS_STATE_DIR:-${WORKING_DIRECTORY:-$HOME}/patch/.compare_platforms_state}/test_update.last"
        if [[ -z "$A_LABEL" && -f "$_STATE_FILE" ]]; then
            A_LABEL=$(tr -d '[:space:]' < "$_STATE_FILE")
            [[ -n "$A_LABEL" ]] && echo "  (A_LABEL 來源: 狀態檔 $_STATE_FILE)" >&2
        fi

        # 掃 ~/patch/，只取「含有 client_* 檔案」且 dir 名符合 YYYYMMDD-HHMM 的目錄
        # （server-only / symbols-only patch 沒有 client_*，不算 client patch）
        _PATCH_DIRS=()
        while IFS= read -r _d; do
            _PATCH_DIRS+=("$_d")
        done < <(
            find "$HOME/patch/" -maxdepth 2 -name 'client_*' -type f 2>/dev/null \
                | awk -F/ '{print $(NF-1)}' \
                | grep -E '^[0-9]{8}-[0-9]{4}$' \
                | sort -u
        )
        if (( ${#_PATCH_DIRS[@]} >= 2 )); then
            [[ -z "$A_LABEL" ]] && { A_LABEL="${_PATCH_DIRS[-2]}"; echo "  (A_LABEL 來源: heuristic ~/patch/ 含 client_* 的倒數第二)" >&2; }
            [[ -z "$B_LABEL" ]] && B_LABEL="${_PATCH_DIRS[-1]}"
        elif (( ${#_PATCH_DIRS[@]} == 1 )); then
            [[ -z "$B_LABEL" ]] && B_LABEL="${_PATCH_DIRS[0]}"
            [[ -z "$A_LABEL" ]] && echo "⚠️  action='test_update' 但 ~/patch/ 只有 1 個 client 版本目錄且無狀態檔，A_LABEL 未知" >&2
        else
            echo "⚠️  action='test_update' 但 ~/patch/ 下無含 client_* 的 YYYYMMDD-HHMM 目錄，label 未知" >&2
        fi
        ;;
    "live_sync")
        ACTION_TITLE="正式機同步（live_sync）"
        [[ -z "$THREAD_TAG" ]] && THREAD_TAG="client_sync"
        (( NO_EXCLUDE_EXPLICIT == 0 )) && NO_EXCLUDE=1

        # A/B 預設（未傳 positional 時自動填）
        : "${WORKING_DIRECTORY:?live_sync 需要 .gamerc 提供 WORKING_DIRECTORY}"
        : "${GAME_TYPE:?live_sync 需要 .gamerc 提供 GAME_TYPE}"
        _DEFAULT_A="$WORKING_DIRECTORY/www/${GAME_TYPE}-TEST_SYNCTOLIVE"
        _DEFAULT_B="$WORKING_DIRECTORY/www/${GAME_TYPE}-TEST"
        [[ -z "$A" ]] && A="$_DEFAULT_A"
        [[ -z "$B" ]] && B="$_DEFAULT_B"

        # label 用「原 A 目錄名稱」vs「B 目錄名稱」
        [[ -z "$A_LABEL" ]] && A_LABEL="$(basename "$A")"
        [[ -z "$B_LABEL" ]] && B_LABEL="$(basename "$B")"

        # ── 前置作業：複製 A 到 /tmp，依 setup.txt 的 NFSExtension 改檔名 ──
        _RESTORE_DIR="/tmp/${GAME_TYPE}-TEST_SYNCTOLIVE_RESTORE"

        [[ -d "$A" ]] || { echo "❌ A 來源目錄不存在: $A" >&2; exit 1; }

        # 清除舊暫存（若存在）— 以 prefix 檢查避免誤刪
        if [[ -d "$_RESTORE_DIR" && "$_RESTORE_DIR" == "/tmp/${GAME_TYPE}-TEST_SYNCTOLIVE_RESTORE" ]]; then
            echo "[live_sync prep] 清除既有暫存: $_RESTORE_DIR"
            rm -rf "$_RESTORE_DIR"
        fi

        echo "[live_sync prep] 複製 $A → $_RESTORE_DIR"
        cp -a "$A" "$_RESTORE_DIR" || { echo "❌ 複製失敗" >&2; exit 1; }

        # 讀 setup.txt 的 NFSExtension（帶點與否由檔案內容決定）
        _SETUP_FILE="$_RESTORE_DIR/setup.txt"
        [[ -f "$_SETUP_FILE" ]] || { echo "❌ setup.txt 不存在: $_SETUP_FILE" >&2; exit 1; }
        _NFS_EXT=$(grep -E '^NFSExtension=' "$_SETUP_FILE" | head -1 | cut -d= -f2- | tr -d '\r\n' | sed 's/[[:space:]]*$//')
        [[ -n "$_NFS_EXT" ]] || { echo "❌ 無法從 setup.txt 解析 NFSExtension" >&2; exit 1; }
        echo "[live_sync prep] NFSExtension='$_NFS_EXT'"

        # 掃所有以 $_NFS_EXT 結尾的「檔案」，去掉結尾改名（衝突覆蓋）
        echo "[live_sync prep] 掃描並改名 *${_NFS_EXT} → 去掉結尾..."
        _RENAMED=0
        while IFS= read -r -d '' _f; do
            _new="${_f%$_NFS_EXT}"
            [[ "$_new" == "$_f" ]] && continue
            mv -f "$_f" "$_new" && _RENAMED=$((_RENAMED + 1))
        done < <(find "$_RESTORE_DIR" -type f -name "*${_NFS_EXT}" -print0)
        echo "[live_sync prep] 已改名 $_RENAMED 個檔案"

        # A 改指向處理後的 restore 目錄；標記 compare 跑完需刪
        A="$_RESTORE_DIR"
        LIVE_SYNC_CLEANUP_PATH="$_RESTORE_DIR"
        ;;
    "")
        # 沒指定 action → 維持 CLI 原行為
        :
        ;;
    *)
        echo "⚠️  未知的 action: '$ACTION'，將用預設 title='Client Patch'" >&2
        ;;
esac

# ── 驗證（action 處理完後）──
[[ -n "$A" && -n "$B" ]] || usage
[[ -d "$A" ]] || { echo "❌ A 目錄不存在: $A" >&2; exit 1; }
[[ -d "$B" ]] || { echo "❌ B 目錄不存在: $B" >&2; exit 1; }

# 組顯示字串：label 有帶就優先顯示 label + 路徑括號；沒有就只顯示路徑
if [[ -n "$A_LABEL" ]]; then
    A_DISPLAY="$A_LABEL ($A)"
else
    A_DISPLAY="$A"
fi
if [[ -n "$B_LABEL" ]]; then
    B_DISPLAY="$B_LABEL ($B)"
else
    B_DISPLAY="$B"
fi

# ── helpers ──

human_duration() {
    local total="$1"
    local h=$((total / 3600))
    local m=$(((total % 3600) / 60))
    local s=$((total % 60))
    if (( h > 0 )); then
        printf '%dh %dm %ds' "$h" "$m" "$s"
    elif (( m > 0 )); then
        printf '%dm %ds' "$m" "$s"
    else
        printf '%ds' "$s"
    fi
}

human_size() {
    awk -v b="$1" 'BEGIN {
        if (b < 1024)             printf "%d B",    b
        else if (b < 1048576)     printf "%.1f KB", b/1024
        else if (b < 1073741824)  printf "%.1f MB", b/1048576
        else                      printf "%.1f GB", b/1073741824
    }'
}

scan_dir() {
    local dir="$1"
    [[ -d "$dir" ]] || return 0

    local prune_args=()
    if (( NO_EXCLUDE == 0 )); then
        for excl in "${COMPARE_PLATFORMS_EXCLUDE_PATHS[@]}"; do
            prune_args+=(-path "./${excl}" -prune -o)
        done
    fi

    (cd "$dir" && find . "${prune_args[@]}" -type f -print0 \
        | while IFS= read -r -d '' f; do
        size=$(stat -c %s "$f" 2>/dev/null) || continue
        md5=$(md5sum "$f" 2>/dev/null | cut -d' ' -f1) || continue
        printf '%s\t%s\t%s\n' "${f#./}" "$size" "$md5"
    done)
}

compare_lists() {
    local a_file="$1"
    local b_file="$2"
    local out_prefix="$3"

    : > "${out_prefix}.only_A"
    : > "${out_prefix}.only_B"
    : > "${out_prefix}.diff"

    awk -F'\t' -v oa="${out_prefix}.only_A" \
                -v ob="${out_prefix}.only_B" \
                -v od="${out_prefix}.diff" \
                -v a_file="$a_file" '
        FILENAME == a_file {
            A_size[$1] = $2
            A_md5[$1]  = $3
            next
        }
        {
            B_size[$1] = $2
            B_md5[$1]  = $3
        }
        END {
            only_a_count=0; only_a_size=0
            only_b_count=0; only_b_size=0
            diff_count=0;   diff_size=0

            for (p in A_md5) {
                if (!(p in B_md5)) {
                    print p "\t" A_size[p] > oa
                    only_a_count++
                    only_a_size += A_size[p]
                } else if (A_md5[p] != B_md5[p]) {
                    d = B_size[p]
                    print p "\t" A_size[p] "\t" B_size[p] "\t" d > od
                    diff_count++
                    diff_size += d
                }
            }
            for (p in B_md5) {
                if (!(p in A_md5)) {
                    print p "\t" B_size[p] > ob
                    only_b_count++
                    only_b_size += B_size[p]
                }
            }
            printf "%d\t%d\t%d\t%d\t%d\t%d\n", \
                only_a_count, only_a_size, \
                only_b_count, only_b_size, \
                diff_count,   diff_size
        }
    ' "$a_file" "$b_file"
}

# ── 發 Google Chat 通知 ──
#   優先序：1. --no-notify → 不發
#          2. --thread-tag <tag> → send_chatbot_text_only_by_thread_tag
#          3. 否則直接 POST 到 GOOGLE_CHAT_WEBHOOK_URL
send_notification() {
    local message="$1"

    if (( DO_NOTIFY == 0 )); then
        echo "[notify] --no-notify，跳過通知"
        return 0
    fi

    if [[ -n "$THREAD_TAG" ]]; then
        local chatbot_script="$HOME/bin/send_chatbot_text_only_by_thread_tag"
        if [[ ! -x "$chatbot_script" ]]; then
            echo "[notify] ⚠️  $chatbot_script 不存在或不可執行，跳過 thread 通知" >&2
            return 1
        fi
        "$chatbot_script" "$THREAD_TAG" "網頁工具操作" "$message" minute 10
        echo "[notify] 已透過 thread_tag=$THREAD_TAG 發送通知"
        return 0
    fi

    local webhook="${GOOGLE_CHAT_WEBHOOK_URL:-}"
    if [[ -z "$webhook" ]]; then
        echo "[notify] ⚠️  GOOGLE_CHAT_WEBHOOK_URL 未設定，跳過通知" >&2
        return 1
    fi

    local json_payload
    json_payload="$(
        /usr/bin/python3 -c 'import json,sys; print(json.dumps({"text": sys.stdin.read()}))' <<< "$message"
    )"

    if /usr/bin/curl -fsS \
        -X POST \
        -H 'Content-Type: application/json; charset=UTF-8' \
        -d "$json_payload" \
        "$webhook" > /dev/null; then
        echo "[notify] 已透過 GOOGLE_CHAT_WEBHOOK_URL 發送通知"
    else
        echo "[notify] ⚠️  通知發送失敗" >&2
        return 1
    fi
}

# ── 主流程 ──

PLATFORMS=("${COMPARE_PLATFORMS_SUBDIRS[@]}")

echo "╔══════════════════════════════════════════════════════════╗"
echo "║           目錄差異比對 (md5 content comparison)          ║"
echo "╚══════════════════════════════════════════════════════════╝"
echo "A (舊): $A_DISPLAY"
echo "B (新): $B_DISPLAY"
echo "開始時間: $START_STR"
echo "Log 檔案: $LOGFILE"
echo "Log URL:  $LOG_URL"
echo "通知模式: $(
    if (( DO_NOTIFY == 0 )); then
        echo "--no-notify (不發)"
    elif [[ -n "$THREAD_TAG" ]]; then
        echo "thread_tag=$THREAD_TAG"
    else
        echo "GOOGLE_CHAT_WEBHOOK_URL"
    fi
)"
echo "Exclude: $(
    if (( NO_EXCLUDE == 1 )); then
        echo "(無，全比)"
    else
        echo "${COMPARE_PLATFORMS_EXCLUDE_PATHS[*]}"
    fi
)"
echo ""
echo "掃描並計算 md5 中..."

for p in "${PLATFORMS[@]}"; do
    [[ -d "$A/$p" ]] || echo "  ⚠️  $A/$p 不存在，視為空" >&2
    [[ -d "$B/$p" ]] || echo "  ⚠️  $B/$p 不存在，視為空" >&2
    echo "  [$p] 掃描 A..."
    scan_dir "$A/$p" > "$TMPDIR/$p.A"
    echo "  [$p] 掃描 B..."
    scan_dir "$B/$p" > "$TMPDIR/$p.B"
done

# Warning 門檻（-1 停用該項；未設時用極大值即無作用）
_WARN_SIZE="${COMPARE_PLATFORMS_WARNING_SIZE_CRITERIA:-999999999999}"
_WARN_NUM="${COMPARE_PLATFORMS_WARNING_NUMBER_CRITERIA:-999999999999}"

# 組 criteria 顯示字串
if (( _WARN_NUM < 0 )) && (( _WARN_SIZE < 0 )); then
    CRITERIA_LINE="皆停用，永遠 ✅"
else
    _num_part="數量：停用"
    (( _WARN_NUM >= 0 )) && _num_part="數量 ≤ $_WARN_NUM"
    _size_part="大小：停用"
    (( _WARN_SIZE >= 0 )) && _size_part="大小 ≤ $(human_size $_WARN_SIZE)"
    CRITERIA_LINE="${_num_part}, ${_size_part}（超過任一 → ❌）"
fi

echo ""
echo "============================================================"
echo "統計結果"
echo "A (舊): $A_DISPLAY"
echo "B (新): $B_DISPLAY"
echo "Warning 門檻: $CRITERIA_LINE"
echo "============================================================"
printf "%-3s %-10s %10s %10s %10s %12s %15s\n" "" "Platform" "A獨有" "B獨有" "內容不同" "差異總數" "差異大小"
printf -- "-------------------------------------------------------------------------\n"

TOTAL_OA=0; TOTAL_OB=0; TOTAL_DC=0; TOTAL_SIZE=0
declare -a PLATFORM_ROWS=()
declare -a PLATFORM_ROWS_FOR_CHAT=()
ANY_EXCEEDED=0

for p in "${PLATFORMS[@]}"; do
    stats=$(compare_lists "$TMPDIR/$p.A" "$TMPDIR/$p.B" "$TMPDIR/$p")
    IFS=$'\t' read -r oa_c oa_s ob_c ob_s d_c d_s <<< "$stats"
    pt_count=$((oa_c + ob_c + d_c))
    # 差異大小只計 B 獨有 + 內容不同（A 獨有不計入，因為新版不需下載）
    pt_size=$((ob_s + d_s))
    pt_size_h=$(human_size $pt_size)

    pt_exceeded=0
    (( _WARN_NUM >= 0 )) && (( pt_count > _WARN_NUM )) && pt_exceeded=1
    (( _WARN_SIZE >= 0 )) && (( pt_size > _WARN_SIZE )) && pt_exceeded=1
    if (( pt_exceeded == 1 )); then
        pt_icon="❌"
        ANY_EXCEEDED=1
    else
        pt_icon="✅"
    fi

    printf "%-3s %-10s %10d %10d %10d %12d %15s\n" \
        "$pt_icon" "$p" "$oa_c" "$ob_c" "$d_c" "$pt_count" "$pt_size_h"
    PLATFORM_ROWS_FOR_CHAT+=("$(printf '%s %-10s A獨有:%-4d B獨有:%-4d 內容不同:%-4d 差異:%s' "$pt_icon" "$p" "$oa_c" "$ob_c" "$d_c" "$pt_size_h")")
    TOTAL_OA=$((TOTAL_OA + oa_c))
    TOTAL_OB=$((TOTAL_OB + ob_c))
    TOTAL_DC=$((TOTAL_DC + d_c))
    TOTAL_SIZE=$((TOTAL_SIZE + pt_size))
done
printf -- "-------------------------------------------------------------------------\n"
GRAND_TOTAL=$((TOTAL_OA + TOTAL_OB + TOTAL_DC))
TOTAL_SIZE_H=$(human_size $TOTAL_SIZE)

# 總計列的 icon（同樣用 OR 邏輯，-1 停用；並以此作為整體狀態）
total_exceeded=0
(( _WARN_NUM >= 0 )) && (( GRAND_TOTAL > _WARN_NUM )) && total_exceeded=1
(( _WARN_SIZE >= 0 )) && (( TOTAL_SIZE > _WARN_SIZE )) && total_exceeded=1
if (( total_exceeded == 1 )); then
    TOTAL_ICON="❌"
    ANY_EXCEEDED=1
else
    TOTAL_ICON="✅"
fi

printf "%-3s %-10s %10d %10d %10d %12d %15s\n" \
    "$TOTAL_ICON" "總計" "$TOTAL_OA" "$TOTAL_OB" "$TOTAL_DC" \
    "$GRAND_TOTAL" "$TOTAL_SIZE_H"

echo ""
echo "============================================================"
echo "細項"
echo "============================================================"

for p in "${PLATFORMS[@]}"; do
    echo ""
    echo "━━━ $p ━━━"
    any_output=0

    if [[ -s "$TMPDIR/$p.only_A" ]]; then
        echo ""
        echo "▶ A 獨有 ($(wc -l < "$TMPDIR/$p.only_A") 個):"
        while IFS=$'\t' read -r path size; do
            printf "  [%s] %s\n" "$(human_size $size)" "$path"
        done < "$TMPDIR/$p.only_A"
        any_output=1
    fi

    if [[ -s "$TMPDIR/$p.only_B" ]]; then
        echo ""
        echo "▶ B 獨有 ($(wc -l < "$TMPDIR/$p.only_B") 個):"
        while IFS=$'\t' read -r path size; do
            printf "  [%s] %s\n" "$(human_size $size)" "$path"
        done < "$TMPDIR/$p.only_B"
        any_output=1
    fi

    if [[ -s "$TMPDIR/$p.diff" ]]; then
        echo ""
        echo "▶ 內容不同 ($(wc -l < "$TMPDIR/$p.diff") 個):"
        while IFS=$'\t' read -r path size_a size_b diff; do
            printf "  [新:%s] %s (A:%s → B:%s)\n" \
                "$(human_size $diff)" "$path" \
                "$(human_size $size_a)" "$(human_size $size_b)"
        done < "$TMPDIR/$p.diff"
        any_output=1
    fi

    [[ "$any_output" -eq 0 ]] && echo "  (無差異)"
done

echo ""
END_TIME=$(date +%s)
END_STR=$(date -d "@$END_TIME" '+%Y-%m-%d %H:%M:%S %Z')
ELAPSED=$((END_TIME - START_TIME))
ELAPSED_H=$(human_duration $ELAPSED)

echo "============================================================"
echo "A (舊):    $A_DISPLAY"
echo "B (新):    $B_DISPLAY"
echo "開始時間: $START_STR"
echo "結束時間: $END_STR"
echo "總計耗用: $ELAPSED_H"
echo "Log 檔案: $LOGFILE"
echo "Log URL:  $LOG_URL"
echo "============================================================"

# machine-readable summary（方便呼叫者 grep）
echo ""
echo "[SUMMARY] total=$GRAND_TOTAL size_bytes=$TOTAL_SIZE size_human=$TOTAL_SIZE_H log_url=$LOG_URL"

# ── 組通知訊息 + 發送 ──

# 整體狀態 icon：有任一超過門檻 → ❌；全都在門檻內 → ✅
if (( ANY_EXCEEDED == 1 )); then
    OVERALL_ICON="❌"
else
    OVERALL_ICON="✅"
fi
TITLE="${OVERALL_ICON} [${GAME_TYPE:-?}-${COUNTRY_CODE_DISPLAY:-?}] ${ACTION_TITLE} 差異比對結果"

if (( GRAND_TOTAL == 0 )); then
    CHAT_MESSAGE="$(cat <<EOF
$TITLE
$START_STR
A (舊): $A_DISPLAY
B (新): $B_DISPLAY
兩個目錄完全一致（扣除 ${COMPARE_PLATFORMS_EXCLUDE_PATHS[*]}）
執行耗時: $ELAPSED_H
Warning 門檻: $CRITERIA_LINE
Log: $LOG_URL
EOF
)"
else
    # 組 per-platform 列
    TABLE_ROWS=""
    for row in "${PLATFORM_ROWS_FOR_CHAT[@]}"; do
        TABLE_ROWS+="${row}"$'\n'
    done
    CHAT_MESSAGE="$(cat <<EOF
$TITLE
$START_STR
A (舊): $A_DISPLAY
B (新): $B_DISPLAY
總計: $GRAND_TOTAL 個差異 / $TOTAL_SIZE_H
執行耗時: $ELAPSED_H
Warning 門檻: $CRITERIA_LINE
Log: $LOG_URL

$TABLE_ROWS
EOF
)"
fi

echo ""
send_notification "$CHAT_MESSAGE" || echo "[notify] 通知發送未成功（不影響 exit code）" >&2

# 確保 tee 把最後的內容寫完
exec >&- 2>&-
wait
