# 大龙虾代码沙箱镜像 / Big Lobster code-execution sandbox image.
#
# 该镜像对齐 Claude 官方 skill 工具链；P1 起支持：
# - Python  : python-docx / openpyxl / python-pptx / pypdf / pdfplumber / pdf2image / Pillow / defusedxml
#             numpy / pandas / pyarrow / duckdb / polars / matplotlib / plotly / scipy / scikit-learn
# - System  : pandoc / libreoffice (soffice) / poppler-utils / chromium
# - Node    : 20+ 全局安装 docx / pptxgenjs / parcel / html-inline 工具链
# - Path B  : 预构建 web-artifacts-builder 项目模板（Vite + React + Tailwind + 40+ shadcn/ui 组件 +
#             parcel/html-inline 已 install），沙箱内 `cp -a /opt/vite-react-shadcn-template`
#             秒级拿到可 `web-artifacts-bundle` 构建的项目，无需运行时 `pnpm install`
#
# 运行时沙箱 `--network none`，因此所有工具 / 库必须镜像内预装；
# pnpm 配置为 offline=true，确保任何意外的 `pnpm add` 调用也只走本地 store.
#
# Build context：must be deploy/（父目录），Dockerfile 位于 sandbox/.
#   build.sh 已自动设置好上下文.
FROM python:3.11-slim-bookworm

# ---- 系统工具链 ----
# Node 版本必须 >= 20：Claude 官方 web-artifacts-builder 脚本拉的 create-vite@latest
# (>=6) 依赖 Node 20+ 的 util.styleText API；Node 18 下 `pnpm create vite` 会报
# `SyntaxError: The requested module 'node:util' does not provide an export named 'styleText'`.
RUN apt-get update && apt-get install -y --no-install-recommends \
        tini \
        bash \
        ca-certificates \
        curl \
        gnupg \
        pandoc \
        libreoffice \
        libreoffice-l10n-zh-cn \
        libreoffice-help-zh-cn \
        poppler-utils \
        chromium \
        tesseract-ocr \
        tesseract-ocr-eng \
        tesseract-ocr-chi-sim \
        fonts-noto-cjk \
        fonts-noto-cjk-extra \
        fonts-wqy-zenhei \
        fonts-wqy-microhei \
        fonts-arphic-uming \
        fonts-arphic-ukai \
        fonts-hanazono \
        libxml2-utils \
        fontconfig \
    && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
    && apt-get install -y --no-install-recommends nodejs \
    && rm -rf /var/lib/apt/lists/*

# ---- 政务公文字体（GB/T 9704-2012《党政机关公文格式》字体白名单） ----
# 来源：zm-ai-server/web/WEB-INF/fonts/；build 脚本在构建前临时拷贝到上下文 `fonts/`，build
# 结束再清理（保持仓库文件不冗余）. 覆盖公文所有字号层级：
#     - 方正小标宋简体 / 方正大标宋简体：标题 / 封面大标题
#     - 仿宋_GB2312 / 仿宋  ：正文、发文字号、署名、成文日期
#     - 楷体_GB2312 / 楷体  ：签发人、领导批示、题词
#     - 黑体               ：一级小标题、强调
#     - 宋体 / 微软雅黑    ：辅助、屏显
#     - Times New Roman   ：英文、数字
# fc-cache 刷新 font cache 后 LibreOffice / docx-js / python-docx / pptxgenjs 生成的
# 文档都能被 soffice PDF 转换正确渲染.
COPY fonts/ /usr/share/fonts/truetype/zhengwu/
RUN chmod -R a+r /usr/share/fonts/truetype/zhengwu \
    && fc-cache -fv /usr/share/fonts/truetype/zhengwu > /dev/null

# ---- Python 白名单 pip 包 ----
# 升级策略（2026-04-24，v3）：全量跟进 latest，包括跨主版本.
#   - python-pptx 0.6.23 → 1.0.2（0.6 → 1.0，API 基本兼容；Python ≥ 3.8）
#   - pypdf      4.2.0  → 6.10.2（跨 v5/v6；移除 PdfMerger / 旧 extractText / 老密码回退）
#   - Pillow     10.4.0 → 12.2.0（跨 v11/v12；移除若干已弃用 image mode/常量）
# 数据分析 / 图表库补充（2026-05-09）：P0 覆盖 dataframe、列式文件、SQL、常用静态/交互图；
# P1 覆盖统计检验、轻量建模、ECharts/Vega-Lite 导出。kaleido v1 需要浏览器内核，系统层预装 chromium.
# 镜像底座 python:3.11 满足以上所有版本下限（3.8 / 3.9）.
RUN pip install --no-cache-dir \
        python-docx==1.2.0 \
        "markitdown[pptx]==0.1.5" \
        lxml==6.1.0 \
        openpyxl==3.1.5 \
        xlsxwriter==3.2.9 \
        python-pptx==1.0.2 \
        pypdf==6.10.2 \
        pypdfium2==5.8.0 \
        pdfplumber==0.11.9 \
        pdf2image==1.17.0 \
        Pillow==12.2.0 \
        reportlab==4.5.0 \
        pytesseract==0.3.13 \
        defusedxml==0.7.1 \
        numpy==2.4.4 \
        pandas==3.0.2 \
        pyarrow==24.0.0 \
        duckdb==1.5.2 \
        polars==1.40.1 \
        matplotlib==3.10.9 \
        seaborn==0.13.2 \
        plotly==6.7.0 \
        kaleido==1.3.0 \
        tabulate==0.10.0 \
        scipy==1.17.1 \
        statsmodels==0.14.6 \
        scikit-learn==1.8.0 \
        pyecharts==2.1.0 \
        altair==6.1.0 \
        vl-convert-python==1.9.0.post1

# ---- Node 全局工具链 ----
# 这些被 web-artifacts-bundle 以及 `node scripts/xxx.js` 直接调用.
# 升级策略（2026-04-24，v3）：
#   - docx 9.0.3 → 9.6.1（修 XML schema 相关 bug；之前考勤管理规定.docx MS Office 打不开就因 9.0.3）
#   - parcel 全家桶 2.12.0 → 2.16.4（累计 bug 修复）
#   - pptxgenjs 3.12.0 → 4.0.1（ESM-first，TS 类型重组；调用处若走 require 需 esm-compat 包装）
#   - pnpm 保持 9.15.0（10.x major 与预构建 vite 模板 lockfile 兼容性待验证，单独起一轮）
RUN npm install -g --omit=dev \
        pnpm@9.15.0 \
        docx@9.6.1 \
        pptxgenjs@4.0.1 \
        react@19.2.6 \
        react-dom@19.2.6 \
        sharp@0.34.5 \
        react-icons@5.6.0 \
        parcel@2.16.4 \
        @parcel/config-default@2.16.4 \
        parcel-resolver-tspaths@0.0.9 \
        jszip@3.10.1 \
        html-inline@1.2.0 \
    && npm cache clean --force

# ---- 非 root 沙箱用户 ----
RUN groupadd -g 10001 sandbox \
    && useradd -u 10001 -g 10001 -M -s /bin/bash -d /home/sandbox sandbox \
    && mkdir -p /home/sandbox /home/sandbox/.config \
    && chown -R 10001:10001 /home/sandbox

# ---- 挂载点 ----
RUN mkdir -p /work /inputs /outputs /skill /opt/pnpm-store \
    && chown -R 10001:10001 /work /outputs /opt/pnpm-store

# ---- pnpm 初始配置（build 期先走 prefer-offline；build 末尾再锁 offline=true）----
RUN printf 'store-dir=/opt/pnpm-store\nprefer-offline=true\nauto-install-peers=true\n' > /etc/pnpmrc

# ---- 预构建 web-artifacts-builder 项目模板 ----
# 策略：
#   1. 把 skill 的 scripts/ 目录临时 COPY 进来（build context = deploy/）
#   2. 用官方 init-artifact.sh 跑一次完整 scaffolding —— 镜像构建期有网
#   3. 再装 bundle-artifact.sh 要求的 parcel 全家桶（在项目 devDependencies 里）
#   4. 预生成 .parcelrc，运行时不再写文件
#   5. 锁定 pnpm offline=true，运行时 `pnpm add/install` 完全不碰网
#   6. 构建产物 chown 给沙箱用户 10001，运行时用 `cp -a` 复制即可用
COPY skills/web-artifacts-builder/scripts/ /tmp/wab-scripts/
RUN cd /opt \
    && bash /tmp/wab-scripts/init-artifact.sh vite-react-shadcn-template \
    && cd vite-react-shadcn-template \
    && pnpm add -D \
        parcel@2.12.0 \
        @parcel/config-default@2.12.0 \
        parcel-resolver-tspaths@0.0.9 \
        html-inline@1.2.0 \
    && printf '{"extends":"@parcel/config-default","resolvers":["parcel-resolver-tspaths","..."]}\n' > .parcelrc \
    && rm -rf /tmp/wab-scripts \
    && printf 'offline=true\n' >> /etc/pnpmrc \
    && chown -R 10001:10001 /opt/vite-react-shadcn-template /opt/pnpm-store

# ---- 离线包装脚本（从 build context COPY，避开 Dockerfile heredoc 兼容性）----
# web-artifacts-init <name>：秒级复制模板到当前目录
# web-artifacts-bundle    ：调 parcel + html-inline 打单 HTML
COPY sandbox/web-artifacts-init   /usr/local/bin/web-artifacts-init
COPY sandbox/web-artifacts-bundle /usr/local/bin/web-artifacts-bundle
RUN chmod +x /usr/local/bin/web-artifacts-init /usr/local/bin/web-artifacts-bundle

# ---- 运行时环境：HOME 与 XDG_* 指向 /home/sandbox（由 SandboxService mount 成 tmpfs）----
# rootfs --read-only 下，/home/sandbox 目录虽然存在但不可写；SandboxService 会在 docker run
# 时加 `--tmpfs /home/sandbox:size=64m,uid=10001,gid=10001,mode=0700`，让 libreoffice / pnpm
# 的 profile / cache 写到内存（每个 run 独立）. fontconfig 走默认 /etc/fonts，无需写.
ENV HOME=/home/sandbox \
    PNPM_HOME=/home/sandbox/.local/share/pnpm \
    XDG_CACHE_HOME=/home/sandbox/.cache \
    XDG_DATA_HOME=/home/sandbox/.local/share \
    XDG_STATE_HOME=/home/sandbox/.local/state \
    XDG_CONFIG_HOME=/home/sandbox/.config \
    NODE_PATH=/usr/lib/node_modules

WORKDIR /outputs

# tini 作 PID 1 防 zombie；运行时 `docker run ... /work/entry.py`
ENTRYPOINT ["/usr/bin/tini", "--", "python"]
