ARG FRAPPE_IMAGE_PREFIX=frappe
ARG FRAPPE_VERSION=version-16
ARG FRAPPE_BRANCH=main
ARG FRAPPE_PATH=https://git.yierp.vip/erp/frappe

FROM ${FRAPPE_IMAGE_PREFIX}/build:${FRAPPE_VERSION} AS builder

USER root
RUN mkdir -p /home/frappe && chown frappe:frappe /home/frappe && \
    apt-get update && \
    apt-get install -y --no-install-recommends nodejs npm yarnpkg && \
    ln -sf /usr/bin/yarnpkg /usr/local/bin/yarn && \
    rm -rf /var/lib/apt/lists/*

ARG FRAPPE_BRANCH
ARG FRAPPE_PATH

USER frappe
WORKDIR /home/frappe

WORKDIR /home/frappe/frappe-bench

# 降低 git/yarn 在弱网络下的握手失败概率
RUN git config --global http.version HTTP/1.1 && \
    git config --global http.lowSpeedLimit 0 && \
    git config --global http.lowSpeedTime 999999 && \
    yarn config set network-timeout 600000 -g

# 克隆 Frappe 到 bench apps 目录（bench 运行期依赖该布局）
RUN mkdir -p apps && git clone --depth 1 -b ${FRAPPE_BRANCH} ${FRAPPE_PATH} apps/frappe

# 将 air-datepicker 从 GitHub git 依赖替换为 npm 包，避免外网 TLS 抖动
RUN node -e 'const fs=require("fs"); const p="/home/frappe/frappe-bench/apps/frappe/package.json"; const pkg=JSON.parse(fs.readFileSync(p,"utf8")); if(pkg.dependencies && pkg.dependencies["air-datepicker"]){ pkg.dependencies["air-datepicker"]="3.6.0"; } fs.writeFileSync(p, JSON.stringify(pkg, null, 2)+"\n");'

# 将 GitHub git 依赖替换为 codeload tarball，避免 git clone TLS 失败
RUN set -e; \
        for f in /home/frappe/frappe-bench/apps/frappe/pyproject.toml /home/frappe/frappe-bench/apps/frappe/requirements*.txt; do \
            [ -f "$f" ] || continue; \
            sed -i -E 's#git\+https://github.com/([^/]+/[^@"]+)@([0-9A-Za-z._-]+)#https://codeload.github.com/\1/tar.gz/\2#g' "$f"; \
        done

# 创建 Python 虚拟环境
RUN python3 -m venv env

ENV PATH="/home/frappe/frappe-bench/env/bin:${PATH}"

# 升级 pip 和安装 wheel
RUN python3 -m pip install --no-cache-dir --upgrade pip wheel

# 复制项目文件
COPY --chown=frappe:frappe . .

# 新版 air-datepicker 不再提供 dist 路径，改写 Frappe 里的旧引用并校验
RUN sed -i 's#air-datepicker/dist/js/datepicker.min.js#air-datepicker/air-datepicker.js#g' /home/frappe/frappe-bench/apps/frappe/frappe/public/js/controls.bundle.js && \
    sed -i 's#~air-datepicker/dist/css/datepicker.min#air-datepicker/air-datepicker.css#g' /home/frappe/frappe-bench/apps/frappe/frappe/public/scss/common/datepicker.scss && \
    sed -i 's#~air-datepicker/air-datepicker.css#air-datepicker/air-datepicker.css#g' /home/frappe/frappe-bench/apps/frappe/frappe/public/scss/common/datepicker.scss && \
    sed -i -E 's#air-datepicker/dist/js/i18n/datepicker\.([A-Za-z-]+)\.js#air-datepicker/locale/\1.js#g' /home/frappe/frappe-bench/apps/frappe/frappe/public/js/frappe/form/controls/datepicker_i18n.js && \
    sed -i -E 's#air-datepicker/locale/datepicker\.([A-Za-z-]+)\.js#air-datepicker/locale/\1.js#g' /home/frappe/frappe-bench/apps/frappe/frappe/public/js/frappe/form/controls/datepicker_i18n.js && \
    ! grep -q 'air-datepicker/dist/' /home/frappe/frappe-bench/apps/frappe/frappe/public/js/controls.bundle.js && \
    ! grep -q 'air-datepicker/dist/' /home/frappe/frappe-bench/apps/frappe/frappe/public/scss/common/datepicker.scss && \
    ! grep -q 'air-datepicker/dist/' /home/frappe/frappe-bench/apps/frappe/frappe/public/js/frappe/form/controls/datepicker_i18n.js

# 验证 Node 安装
RUN node --version && npm --version

# 强制安装 frappe 前端依赖，避免运行时缺少 fast-glob 等模块
RUN cd /home/frappe/frappe-bench/apps/frappe && \
    unset NODE_ENV npm_config_production && \
    for i in 1 2 3; do \
        yarn install --check-files && break; \
        if [ "$i" -eq 3 ]; then \
            echo "❌ yarn install failed after 3 attempts"; \
            exit 1; \
        fi; \
        echo "⚠️ yarn install failed, retrying (attempt $((i + 1))/3)"; \
    done

# 安装 frappe
RUN for i in 1 2 3; do \
        python3 -m pip install --no-cache-dir -e /home/frappe/frappe-bench/apps/frappe && break; \
        if [ "$i" -eq 3 ]; then \
            echo "❌ pip install frappe failed after 3 attempts"; \
            exit 1; \
        fi; \
        echo "⚠️ pip install frappe failed, retrying (attempt $((i + 1))/3)"; \
    done

# 安装 apps.json 中定义的应用
RUN --mount=type=secret,id=apps_json,uid=1000,gid=1000,mode=0444 \
    if [ -f /run/secrets/apps_json ]; then \
        echo "📦 从 apps.json 安装应用..."; \
        export APPS_JSON_BASE64=$(cat /run/secrets/apps_json | base64 -w 0); \
        echo ${APPS_JSON_BASE64} | base64 -d > apps/apps.json; \
        echo "✅ apps.json 内容:"; \
        cat apps/apps.json; \
    fi && \
    if [ -f apps/apps.json ]; then \
        jq -r '.[] | [.url, .branch] | @tsv' apps/apps.json | while IFS="$(printf '\t')" read -r url branch; do \
            [ -z "$url" ] && continue; \
            app_name=$(basename "$url" .git); \
            if [ "$app_name" = "frappe" ]; then \
                echo "ℹ️ 跳过 frappe（已预先克隆到 apps/frappe）"; \
                continue; \
            fi; \
            echo "📥 获取应用: ${app_name} (${branch})"; \
            bench get-app --branch "$branch" "$url"; \
            if [ -f "apps/${app_name}/setup.py" ] || [ -f "apps/${app_name}/pyproject.toml" ]; then \
                echo "📦 安装应用: ${app_name}"; \
                python3 -m pip install --no-cache-dir -e "apps/${app_name}"; \
            else \
                echo "⚠️  应用 ${app_name} 没有 setup.py，跳过 pip 安装"; \
            fi; \
        done; \
    else \
        echo "⚠️  未找到 apps.json，跳过应用安装"; \
    fi

# 清理 .git 目录以减小镜像大小
RUN find apps -mindepth 1 -path "*/.git" | xargs rm -fr

# 为所有包含 package.json 的应用安装前端依赖
RUN set -e; \
    cd /home/frappe/frappe-bench; \
    find apps -mindepth 1 -maxdepth 1 -type d | while read -r app_dir; do \
        if [ -f "$app_dir/package.json" ]; then \
            echo "Installing JS deps for $(basename "$app_dir")"; \
            (cd "$app_dir" && unset NODE_ENV npm_config_production && \
                for i in 1 2 3; do \
                    yarn install --check-files && break; \
                    if [ "$i" -eq 3 ]; then \
                        echo "❌ yarn install failed for $(basename "$app_dir") after 3 attempts"; \
                        exit 1; \
                    fi; \
                    echo "⚠️ yarn install failed for $(basename "$app_dir"), retrying (attempt $((i + 1))/3)"; \
                done); \
        fi; \
    done

FROM ${FRAPPE_IMAGE_PREFIX}/base:${FRAPPE_VERSION} AS backend

USER root

RUN apt-get update && \
    apt-get install -y --no-install-recommends nodejs npm yarnpkg && \
    ln -sf /usr/bin/yarnpkg /usr/local/bin/yarn && \
    rm -rf /var/lib/apt/lists/*

# 优先使用 base 镜像中 nvm 的 Node 24，满足前端构建对 node>=24 的要求
RUN set -e; \
    NODE_BIN_DIR="$(dirname "$(ls -1 /home/frappe/.nvm/versions/node/*/bin/node | sort | tail -n1)")"; \
    ln -sf "$NODE_BIN_DIR/node" /usr/local/bin/node; \
    ln -sf "$NODE_BIN_DIR/npm" /usr/local/bin/npm; \
    ln -sf "$NODE_BIN_DIR/npx" /usr/local/bin/npx; \
    if [ -x "$NODE_BIN_DIR/yarn" ]; then ln -sf "$NODE_BIN_DIR/yarn" /usr/local/bin/yarn; fi

# 复制完整 bench（含 env），确保运行时具备 frappe 依赖
COPY --from=builder /home/frappe/frappe-bench /home/frappe/frappe-bench

COPY resources/core/main-entrypoint.sh /usr/local/bin/main-entrypoint.sh
RUN chmod 755 /usr/local/bin/main-entrypoint.sh

COPY resources/core/check-assets.sh /usr/local/bin/check-assets.sh
RUN chmod 755 /usr/local/bin/check-assets.sh

WORKDIR /home/frappe/frappe-bench

ENV PATH="/home/frappe/frappe-bench/env/bin:${PATH}"

# 设置环境变量
ENV BENCH_DEVELOPMENT=1
ENV FRAPPE_ENV=production

ENTRYPOINT ["/usr/local/bin/main-entrypoint.sh"]
CMD ["bench", "serve"]