# ============================================
# 3D家具安装展示系统 - Docker构建文件
# ============================================
# 基于 flnxi_sucai 项目的 Dockerfile 优化
# 支持本地缓存包，减少网络依赖

# ============================================
# 阶段 1: 基础镜像
# ============================================
FROM node:18-alpine AS base

# 使用阿里云镜像源加速（中国网络优化）
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# ============================================
# 阶段 2: 依赖安装 (deps)
# ============================================
FROM base AS deps

# 安装构建时依赖
# Three.js 和 3D 相关包需要的系统依赖
RUN apk add --no-cache --virtual .build-deps \
    libc6-compat \
    openssl3 \
    openssl-dev \
    # 3D 图形处理相关依赖
    mesa-dev \
    mesa-gl \
    # 编译工具（用于编译原生模块）
    python3 \
    make \
    g++ \
    pkgconfig

WORKDIR /app

# 复制依赖文件（利用 Docker 缓存层）
COPY package.json package-lock.json* ./

# 配置 npm 使用国内镜像源
RUN npm config set registry https://registry.npmmirror.com/

# 尝试使用本地缓存的 node_modules
# 如果本地缓存存在，直接复制；否则通过 npm 安装
COPY local-packages/npm-cache/node_modules* ./node_modules_cache/
RUN if [ -d "./node_modules_cache" ] && [ "$(ls -A ./node_modules_cache)" ]; then \
        echo "使用本地缓存的 node_modules" && \
        cp -r ./node_modules_cache/* ./node_modules/ 2>/dev/null || true && \
        npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit; \
    else \
        echo "本地缓存不可用，从网络安装依赖" && \
        npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit; \
    fi

# 清理构建依赖，保留运行时库
RUN apk del .build-deps && \
    npm config delete registry && \
    apk add --no-cache \
    libc6-compat \
    ca-certificates \
    openssl3 \
    # 3D 渲染运行时库
    mesa-gl

# ============================================
# 阶段 3: 构建应用 (builder)
# ============================================
FROM base AS builder

# 构建参数
ARG DATABASE_URL="postgresql://user:password@localhost:5432/placeholder_db?schema=public"
ARG NEXTAUTH_URL=""
ARG NEXT_PUBLIC_APP_URL=""

# Prisma 引擎缓存配置
ARG PRISMA_ENGINE_CACHE_FILE_NAME="libquery_engine-linux-musl-openssl-3.0.x.so.node"
ARG PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME="schema-engine-linux-musl-openssl-3.0.x"

# 环境变量设置
ENV PRISMA_ENGINE_CACHE_FILE_NAME=${PRISMA_ENGINE_CACHE_FILE_NAME}
ENV PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME=${PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME}
ENV DATABASE_URL=${DATABASE_URL}
ENV NEXTAUTH_URL=${NEXTAUTH_URL}
ENV NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1

WORKDIR /app

# 安装 OpenSSL 3（Prisma 需要）
RUN apk add --no-cache openssl3

# 从 deps 阶段复制 node_modules
COPY --from=deps /app/node_modules ./node_modules

# 复制应用源代码
COPY . .

# 配置 Prisma 引擎缓存路径
ENV PRISMA_ENGINE_CACHE_PATH=/app/local-packages/prisma-engines/${PRISMA_ENGINE_CACHE_FILE_NAME}
ENV PRISMA_SCHEMA_ENGINE_CACHE_PATH=/app/local-packages/prisma-engines/${PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME}

# 设置 Prisma 引擎缓存（如果本地缓存存在）
RUN set -ex && \
    if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
        echo "检测到本地 Prisma 查询引擎缓存: ${PRISMA_ENGINE_CACHE_PATH}" && \
        PRISMA_ENGINE_VERSION=$(node -p "require('@prisma/engines-version/package.json').prisma.enginesVersion") && \
        TARGET_DIR="/root/.cache/prisma/master/${PRISMA_ENGINE_VERSION}/linux-musl-openssl-3.0.x" && \
        mkdir -p "${TARGET_DIR}" && \
        cp "${PRISMA_ENGINE_CACHE_PATH}" "${TARGET_DIR}/libquery_engine.so.node" && \
        gzip -c "${PRISMA_ENGINE_CACHE_PATH}" > "${TARGET_DIR}/libquery_engine.so.node.gz" && \
        sha256sum "${TARGET_DIR}/libquery_engine.so.node.gz" | awk '{print $1}' > "${TARGET_DIR}/libquery_engine.so.node.gz.sha256"; \
    else \
        echo "未找到本地 Prisma 查询引擎缓存，将在线下载"; \
    fi && \
    if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
        echo "检测到本地 Prisma schema 引擎缓存: ${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" && \
        PRISMA_ENGINE_VERSION=$(node -p "require('@prisma/engines-version/package.json').prisma.enginesVersion") && \
        TARGET_DIR="/root/.cache/prisma/master/${PRISMA_ENGINE_VERSION}/linux-musl-openssl-3.0.x" && \
        mkdir -p "${TARGET_DIR}" && \
        cp "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" "${TARGET_DIR}/schema-engine" && \
        chmod +x "${TARGET_DIR}/schema-engine" && \
        gzip -c "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" > "${TARGET_DIR}/schema-engine.gz" && \
        sha256sum "${TARGET_DIR}/schema-engine.gz" | awk '{print $1}' > "${TARGET_DIR}/schema-engine.gz.sha256"; \
    else \
        echo "未找到本地 Prisma schema 引擎缓存，将在线下载"; \
    fi

# 生成 Prisma Client（构建阶段使用占位 DATABASE_URL，避免 prisma.config.ts 报错）
RUN set -ex && \
    export DATABASE_URL="${DATABASE_URL:-postgresql://user:password@localhost:5432/placeholder_db?schema=public}" && \
    if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
        export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
        export PRISMA_CLIENT_ENGINE_TYPE=library && \
        export PRISMA_CLI_QUERY_ENGINE_TYPE=library && \
        echo "使用本地 Prisma 查询引擎缓存生成 Client"; \
    else \
        echo "使用在线下载的 Prisma 引擎"; \
        unset PRISMA_QUERY_ENGINE_LIBRARY PRISMA_CLIENT_ENGINE_TYPE PRISMA_CLI_QUERY_ENGINE_TYPE; \
    fi && \
    if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
        export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" && \
        echo "使用本地 Prisma schema 引擎缓存"; \
    else \
        unset PRISMA_SCHEMA_ENGINE_BINARY; \
    fi && \
    if npx prisma generate; then \
        echo "Prisma Client 生成成功"; \
    else \
        echo "Prisma 官方源失败，尝试使用镜像源..." && \
        PRISMA_ENGINES_MIRROR="https://registry.npmmirror.com/-/binary/prisma/" npx prisma generate; \
    fi

# 验证 Prisma Client 生成
RUN if [ ! -d "node_modules/.prisma" ]; then \
        echo "错误: Prisma Client 未生成" >&2 && exit 1; \
    fi

# 构建 Next.js 应用（standalone 模式）
RUN set -ex && \
    if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
        export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
        export PRISMA_CLIENT_ENGINE_TYPE=library && \
        export PRISMA_CLI_QUERY_ENGINE_TYPE=library; \
    else \
        unset PRISMA_QUERY_ENGINE_LIBRARY PRISMA_CLIENT_ENGINE_TYPE PRISMA_CLI_QUERY_ENGINE_TYPE; \
    fi && \
    if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
        export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}"; \
    else \
        unset PRISMA_SCHEMA_ENGINE_BINARY; \
    fi && \
    npm run build

# 验证构建产物
RUN if [ ! -f ".next/standalone/server.js" ]; then \
        echo "错误: standalone 输出未生成，请检查 next.config.js" >&2 && \
        exit 1; \
    fi

# ============================================
# 阶段 4: 生产运行 (runner)
# ============================================
FROM base AS runner

WORKDIR /app

# 设置生产环境变量
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

# 安装运行时依赖
RUN apk add --no-cache \
    libc6-compat \
    ca-certificates \
    openssl3 \
    # 3D 渲染运行时库
    mesa-gl \
    # 字体支持（3D 文本渲染）
    fontconfig \
    ttf-dejavu

# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

# 从 builder 阶段复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

# 复制必要的文件
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
COPY --from=builder --chown=nextjs:nodejs /app/src/lib ./src/lib

# 复制 Prisma 相关文件
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/prisma ./node_modules/prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin ./node_modules/.bin

# 创建上传目录
RUN mkdir -p /app/uploads && \
    chown -R nextjs:nodejs /app/uploads && \
    chmod -R 755 /app/uploads

# 切换到非 root 用户
USER nextjs

EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/api/health || exit 1

# 启动应用
CMD ["node", "server.js"]