#!/bin/bash
# 通用Docker镜像构建+推送脚本（local cache为主 + registry cache共享）
# 用法: docker_build_push.sh [--no-cache] <Dockerfile> <image_tag> <cache_ref> [build_arg...]
set -eu

NO_CACHE_FLAG=""
if [ "$1" = "--no-cache" ]; then
  NO_CACHE_FLAG="--no-cache"
  shift
  echo "模式: --no-cache (不使用缓存，全新构建)"
fi

DOCKERFILE="$1"
IMAGE_TAG="$2"
CACHE_REF="$3"
shift 3
BUILD_ARGS=""
for arg in "$@"; do
  BUILD_ARGS="$BUILD_ARGS --build-arg $arg"
done

if ! docker buildx inspect ci-builder > /dev/null 2>&1; then
  docker buildx create --use --name ci-builder --driver docker-container
  echo "Created ci-builder"
else
  docker buildx use ci-builder
  echo "Using existing ci-builder"
fi
docker buildx inspect --bootstrap

# 从cache_ref中提取缓存名称（如 api-cache:develop -> api-cache-develop）
CACHE_NAME=$(echo "$CACHE_REF" | tr '/' '_' | tr ':' '-')
LOCAL_CACHE_DIR="/tmp/buildx-cache/${CACHE_NAME}"

mkdir -p "$LOCAL_CACHE_DIR"

# 缓存源：local优先（带自动修复），registry兜底读写
# 本地缓存损坏时自动清理后重试，避免snapshot not found导致构建全挂
build_with_cache_retry() {
  local attempt=1
  local max_attempts=2
  while [ $attempt -le $max_attempts ]; do
    local build_output
    local exit_code
    set +e
    build_output=$(docker buildx build \
      $NO_CACHE_FLAG \
      $BUILD_ARGS \
      --cache-from "type=local,src=${LOCAL_CACHE_DIR}" \
      --cache-from "type=registry,ref=${CACHE_REF}" \
      --cache-to "type=local,dest=${LOCAL_CACHE_DIR},mode=max" \
      --cache-to "type=registry,ref=${CACHE_REF},mode=max,ignore-error=true" \
      -f "${DOCKERFILE}" \
      -t "${IMAGE_TAG}" \
      --push \
      . 2>&1)
    exit_code=$?
    set -e
    if [ $exit_code -eq 0 ]; then
      echo "$build_output"
      return 0
    fi
    # 检测到缓存损坏类错误，清掉本地缓存重试
    if echo "$build_output" | grep -qE "parent snapshot.*not found|snapshot.*does not exist|cache.*corrupt|failed to compute cache key"; then
      echo "$build_output"
      echo ""
      echo "⚠️  Local cache appears corrupted, cleaning up and retrying (attempt $attempt/$max_attempts)..."
      rm -rf "${LOCAL_CACHE_DIR}"
      mkdir -p "${LOCAL_CACHE_DIR}"
      # 清理buildx builder的内部snapshot状态
      docker buildx prune -f -a >/dev/null 2>&1 || true
      attempt=$((attempt + 1))
    else
      # 非缓存类错误，直接输出并返回
      echo "$build_output"
      return $exit_code
    fi
  done
  # 重试完还是失败，不用本地缓存最后试一次（只从registry读）
  echo "⚠️  All cached attempts failed, building without local cache..."
  docker buildx build \
    $NO_CACHE_FLAG \
    $BUILD_ARGS \
    --cache-from "type=registry,ref=${CACHE_REF}" \
    --cache-to "type=local,dest=${LOCAL_CACHE_DIR},mode=max" \
    --cache-to "type=registry,ref=${CACHE_REF},mode=max,ignore-error=true" \
    -f "${DOCKERFILE}" \
    -t "${IMAGE_TAG}" \
    --push \
    .
}

echo "=== Step 1: Build & push image (local cache + registry cache, with auto-repair) ==="
echo "Local cache: ${LOCAL_CACHE_DIR}"
echo "Registry cache: ${CACHE_REF}"
echo ""

build_with_cache_retry

echo ""
echo "Image pushed: ${IMAGE_TAG}"
echo "Local cache updated"
echo "Registry cache updated (if supported)"

echo ""
echo "Build completed: ${IMAGE_TAG}"
