#!/bin/sh
# LFS Pre-Push Hook — push 前显示 LFS 文件清单并要求确认
# Issue: OS-GBL-F-002
#
# 功能：
#   1. 检测本次 push 涉及的 LFS 文件，显示清单和总大小
#   2. >500MB 的文件标记警告
#   3. 用户确认后执行 git lfs pre-push 上传
#
# 环境变量：
#   LFS_PREPUSH_SKIP=1  跳过确认（CI/CD 用）
#
# 兼容性：POSIX sh + BSD awk（macOS 原生环境）

REMOTE="$1"
URL="$2"

# --- 捕获 stdin（ref 数据），后续 replay 给 git lfs pre-push ---
INPUT=""
while IFS= read -r line; do
    if [ -z "$INPUT" ]; then
        INPUT="$line"
    else
        INPUT="$INPUT
$line"
    fi
done

# --- 检查 git-lfs 是否可用 ---
if ! command -v git-lfs >/dev/null 2>&1 && ! git lfs version >/dev/null 2>&1; then
    echo "pre-push: git-lfs not found, skipping LFS check"
    exit 0
fi

# --- 收集所有 ref 涉及的 LFS 文件 ---
LFS_LIST=""

process_ref() {
    local_ref="$1"
    local_sha="$2"
    remote_ref="$3"
    remote_sha="$4"

    ZERO="0000000000000000000000000000000000000000"

    # 删除分支 → 跳过
    if [ "$local_sha" = "$ZERO" ]; then
        return
    fi

    # 确定比较基准
    if [ "$remote_sha" = "$ZERO" ]; then
        # 新分支：找与默认分支的 merge-base
        base=""
        for candidate in main master develop; do
            if git rev-parse --verify "refs/remotes/origin/$candidate" >/dev/null 2>&1; then
                base=$(git merge-base "refs/remotes/origin/$candidate" "$local_sha" 2>/dev/null)
                break
            fi
        done
        if [ -z "$base" ]; then
            # 无法找到基准，列出该分支所有 LFS 文件
            base=""
        fi
    else
        base="$remote_sha"
    fi

    # 获取 LFS 文件列表（带大小）
    if [ -n "$base" ]; then
        files=$(git lfs ls-files --size "$base" "$local_sha" 2>/dev/null)
    else
        files=$(git lfs ls-files --size "$local_sha" 2>/dev/null)
    fi

    if [ -n "$files" ]; then
        LFS_LIST="$LFS_LIST
$files"
    fi
}

# 解析每一行 ref 数据
if [ -n "$INPUT" ]; then
    echo "$INPUT" | while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do
        if [ -n "$local_ref" ]; then
            process_ref "$local_ref" "$local_sha" "$remote_ref" "$remote_sha"
        fi
    done
fi

# 因为上面的 while 在子 shell 中，LFS_LIST 不会传递回来
# 重新在当前 shell 处理
LFS_LIST=""
if [ -n "$INPUT" ]; then
    set -f  # 禁用 glob
    OLD_IFS="$IFS"
    IFS='
'
    for line in $INPUT; do
        IFS="$OLD_IFS"
        local_ref=$(echo "$line" | awk '{print $1}')
        local_sha=$(echo "$line" | awk '{print $2}')
        remote_ref=$(echo "$line" | awk '{print $3}')
        remote_sha=$(echo "$line" | awk '{print $4}')

        ZERO="0000000000000000000000000000000000000000"

        # 删除分支 → 跳过
        if [ "$local_sha" = "$ZERO" ]; then
            continue
        fi

        # 确定比较基准
        base=""
        if [ "$remote_sha" = "$ZERO" ]; then
            for candidate in main master develop; do
                if git rev-parse --verify "refs/remotes/origin/$candidate" >/dev/null 2>&1; then
                    base=$(git merge-base "refs/remotes/origin/$candidate" "$local_sha" 2>/dev/null)
                    break
                fi
            done
        else
            base="$remote_sha"
        fi

        # 获取 LFS 文件列表
        if [ -n "$base" ]; then
            files=$(git lfs ls-files --size "$base" "$local_sha" 2>/dev/null)
        else
            files=$(git lfs ls-files --size "$local_sha" 2>/dev/null)
        fi

        if [ -n "$files" ]; then
            LFS_LIST="$LFS_LIST
$files"
        fi

        IFS='
'
    done
    IFS="$OLD_IFS"
    set +f
fi

# --- 去重并解析 ---
# git lfs ls-files --size 输出格式: <oid> <indicator> <path> (<size>)
# 示例: abc1234567 * assets/logo.png (1.2 MB)

if [ -z "$LFS_LIST" ] || [ "$(echo "$LFS_LIST" | sed '/^$/d' | wc -l)" -eq 0 ]; then
    # 无 LFS 文件 → 静默执行 git lfs pre-push 并放行
    echo "$INPUT" | git lfs pre-push "$@"
    exit $?
fi

# 按文件路径去重
DEDUPED=$(echo "$LFS_LIST" | sed '/^$/d' | awk '!seen[$3]++')
FILE_COUNT=$(echo "$DEDUPED" | wc -l | awk '{print $1}')

# --- 非 TTY 或 CI 模式 → 自动放行 ---
if [ "${LFS_PREPUSH_SKIP:-0}" = "1" ]; then
    echo "$INPUT" | git lfs pre-push "$@"
    exit $?
fi

if [ ! -t 0 ] && [ ! -t 1 ]; then
    # 非交互环境，自动放行
    echo "$INPUT" | git lfs pre-push "$@"
    exit $?
fi

# --- 显示 LFS 文件清单 ---
echo ""
echo "=========================================="
echo "  LFS Pre-Push: $FILE_COUNT file(s) detected"
echo "=========================================="
echo ""

TOTAL_BYTES=0
HAS_LARGE=0

echo "$DEDUPED" | while IFS= read -r entry; do
    # 提取路径和大小
    path=$(echo "$entry" | awk '{print $3}')
    size_str=$(echo "$entry" | sed 's/.*(\(.*\))/\1/')

    # 解析大小为字节数（用于判断 >500MB）
    size_num=$(echo "$size_str" | awk '{print $1}')
    size_unit=$(echo "$size_str" | awk '{print $2}')

    bytes=0
    case "$size_unit" in
        B)   bytes=$(echo "$size_num" | awk '{printf "%.0f", $1}') ;;
        KB)  bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1024}') ;;
        MB)  bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1048576}') ;;
        GB)  bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1073741824}') ;;
    esac

    # 检查是否超过 500MB (524288000 bytes)
    is_large=$(echo "$bytes" | awk '{if ($1 > 524288000) print 1; else print 0}')

    if [ "$is_large" = "1" ]; then
        printf "  %-50s %s  %s\n" "$path" "$size_str" "[!] >500MB"
    else
        printf "  %-50s %s\n" "$path" "$size_str"
    fi
done

echo ""
echo "------------------------------------------"
echo "  Total: $FILE_COUNT file(s)"
echo "------------------------------------------"
echo ""

# --- 确认提示 ---
printf "Proceed with LFS upload? [y/N] "

# 从 /dev/tty 读取用户输入（因为 stdin 已被 git 占用）
if read -r answer < /dev/tty 2>/dev/null; then
    case "$answer" in
        [yY]|[yY][eE][sS])
            echo "Uploading LFS files..."
            echo "$INPUT" | git lfs pre-push "$@"
            exit $?
            ;;
        *)
            echo "Push aborted by user."
            exit 1
            ;;
    esac
else
    echo "Cannot read from terminal, aborting."
    exit 1
fi
