ARG BASE_IMAGE=sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/desktop:latest
FROM ${BASE_IMAGE}

ARG NODE_MAJOR=24
# TARGETARCH 由 docker buildx 自动注入（值为 amd64 / arm64 等）。
# 本镜像按目标架构二选一安装浏览器（task #64）：
#   - amd64 → Google Chrome stable（apt 源 dl.google.com，自带 H.264/AAC，
#     指纹更贴近真人，反爬触发率低）；
#   - arm64 → playwright 自带 chromium（Google 不发 chrome 的 Linux arm64
#     build；接受 codec 缺失 + 指纹略劣的硬约束 trade-off）。
ARG TARGETARCH

ENV DEBIAN_FRONTEND=noninteractive \
    LANG=C.UTF-8 \
    LC_ALL=C.UTF-8 \
    DOTNET_ROOT=/usr/share/dotnet \
    DOTNET_CLI_TELEMETRY_OPTOUT=1 \
    DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 \
    NUGET_XMLDOC_MODE=skip \
    NODE_PATH=/usr/lib/node_modules \
    NPM_CONFIG_REGISTRY=https://registry.npmmirror.com \
    COREPACK_NPM_REGISTRY=https://registry.npmmirror.com \
    PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple \
    PIP_TRUSTED_HOST=mirrors.cloud.tencent.com \
    PIPX_HOME=/opt/pipx \
    PIPX_BIN_DIR=/usr/local/bin \
    PATH=/opt/browser-venv/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin \
    GTK_IM_MODULE=fcitx \
    QT_IM_MODULE=fcitx \
    XMODIFIERS=@im=fcitx \
    INPUT_METHOD=fcitx \
    SDL_IM_MODULE=fcitx \
    TA_SANDBOX_DNS_SERVERS=1.1.1.1,8.8.8.8,223.5.5.5 \
    UV_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple \
    UV_LINK_MODE=copy \
    PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
    REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding \
    XCURSOR_SIZE=64

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

USER root

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        ca-certificates \
        curl \
        gnupg \
    && install -d -m 0755 /etc/apt/keyrings \
    && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
        | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
        > /etc/apt/sources.list.d/nodesource.list \
    && curl -fsSL https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb \
        -o /tmp/packages-microsoft-prod.deb \
    && dpkg -i /tmp/packages-microsoft-prod.deb \
    # 注：浏览器（chrome / chromium）由后面的架构分支段按 TARGETARCH 安装，
    # Google Chrome 官方 apt 源也只在 amd64 分支临时加，避免 arm64 build 时
    # 因 deb 行 `arch=amd64` 段阻挡。
    && apt-get update \
    && apt-get install -y --no-install-recommends \
        dbus-x11 \
        dotnet-sdk-8.0 \
        fcitx5 \
        fcitx5-chinese-addons \
        fcitx5-frontend-gtk3 \
        fcitx5-frontend-gtk4 \
        fcitx5-frontend-qt5 \
        fonts-dejavu-core \
        fonts-liberation \
        fonts-noto-cjk \
        fonts-noto-cjk-extra \
        fonts-wqy-microhei \
        fonts-wqy-zenhei \
        fonts-arphic-ukai \
        fonts-arphic-uming \
        git \
        im-config \
        jq \
        less \
        libreoffice-writer \
        locales \
        mousepad \
        nano \
        nodejs \
        patch \
        pipx \
        procps \
        python3 \
        python3-pip \
        python3-venv \
        scrot \
        unzip \
        vim \
        wget \
        pandoc \
        xdotool \
        zip \
    && sed -i 's/DEFAULT_LOCALE = null;/DEFAULT_LOCALE = "zh_CN";/' /usr/share/novnc/app/localization.js \
    && locale-gen C.UTF-8 \
    # 安装 playwright python sync 客户端到独立 venv：
    # - service 层一律 `playwright.chromium.connect_over_cdp("http://127.0.0.1:9222")`
    #   走 CDP 协议连接已启动浏览器（amd64 是 google-chrome、arm64 是 playwright
    #   chromium，二者监听 9222 端口的协议相同）。
    # - amd64 镜像不需要 playwright 自带的 chromium 二进制（chrome 由 apt 装），
    #   省 ~250MB；arm64 镜像因为没有 chrome Linux build，必须走 playwright
    #   `install --with-deps chromium` 拉官方 chromium，由架构分支段处理。
    # - 上层禁止 `p.chromium.launch()` 路径，启动浏览器统一走 ta-open-browser
    #   脚本（amd64 上 google-chrome / arm64 上经 shim 转发到 playwright chromium）。
      && python3 -m venv /opt/browser-venv \
      && /opt/browser-venv/bin/pip install --no-cache-dir --upgrade pip \
    && /opt/browser-venv/bin/pip install --no-cache-dir 'playwright==1.52.0' \
    && PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install uv \
    && npm install -g npm@latest corepack \
    && corepack enable \
    # 浏览器架构分支（task #64）：根据 TARGETARCH 二选一安装浏览器。
    # - amd64：加 Google Chrome 官方 apt 源（dl.google.com，deb 行写死
    #   `arch=amd64` 是 google 唯一支持的架构），装 google-chrome-stable，
    #   `/usr/bin/google-chrome` 由 apt 包提供软链。
    # - arm64：playwright install --with-deps chromium，把 chromium 二进制装到
    #   `/ms-playwright/chromium-*/chrome-linux/chrome`；由稍后 COPY 的
    #   `scripts/google-chrome` shim 把对外命令名转发到该路径，业务代码不感知。
    # - 其它架构：直接报错（目前不支持）。
    && if [ "$TARGETARCH" = "amd64" ]; then \
          curl -fsSL https://dl.google.com/linux/linux_signing_key.pub \
              | gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg \
          && echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main" \
              > /etc/apt/sources.list.d/google-chrome.list \
          && apt-get update \
          && apt-get install -y --no-install-recommends google-chrome-stable ; \
       elif [ "$TARGETARCH" = "arm64" ]; then \
          /opt/browser-venv/bin/playwright install --with-deps chromium ; \
       else \
          echo "task #64：本镜像仅支持 amd64 / arm64，当前 TARGETARCH=$TARGETARCH" >&2 ; \
          exit 1 ; \
       fi \
    # 反爬指纹补丁（2026-05-24 用户裁决"反爬指纹仍需注入，可以装到 playwright 中"）：
    # - 对 playwright python 包内嵌的 Node.js driver（`.../site-packages/playwright/driver/package/`）
    #   应用 `rebrowser-patches`，patch 后效果固化到该 driver 的 JS 源文件。
    # - playwright python 客户端到浏览器之间所有 CDP 命令都经过这个 patched driver
    #   （python ↔ stdio ↔ node driver ↔ CDP ↔ chrome / chromium），因此
    #   `connect_over_cdp` 接 amd64 google-chrome 或 arm64 playwright chromium
    #   同样生效——补丁修的核心问题（`Runtime.Enable` CDP 命令泄露）正是 CDP
    #   模式下最常被检测的环节，与下游浏览器 build 无关。
    # - 运行期 fix mode 由 ENV `REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding` 控制
    #   （见上方 ENV 段），无需按调用粒度开关。
    # - rebrowser-patches 1.0.19 fully tested 的 playwright-core 版本为 1.52.0，
    #   不要无 pin 升到 1.60+，否则补丁目标文件布局不匹配。
    && DRIVER_PACKAGE_DIR="$(/opt/browser-venv/bin/python -c 'import os, playwright; print(os.path.join(os.path.dirname(playwright.__file__), "driver", "package"))')" \
    && [ -d "$DRIVER_PACKAGE_DIR" ] || { echo "playwright driver package 目录缺失: $DRIVER_PACKAGE_DIR" >&2; exit 1; } \
    && npx --yes rebrowser-patches@1.0.19 patch --packagePath "$DRIVER_PACKAGE_DIR" \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /root/.npm

COPY fonts/ /tmp/turbo-agent-fonts/
COPY fontconfig/local.conf /etc/fonts/local.conf

RUN install -d -m 0755 /usr/local/share/fonts/turbo-agent /etc/fonts/conf.d \
    && find /tmp/turbo-agent-fonts -type f \
        \( -iname '*.ttf' -o -iname '*.ttc' -o -iname '*.otf' \) \
        -exec cp -v {} /usr/local/share/fonts/turbo-agent/ \; \
    && fc-cache -f -v \
    && rm -rf /tmp/turbo-agent-fonts

RUN mkdir -p /tmp/.X11-unix /workspace /home/desktop \
    && chmod 1777 /tmp/.X11-unix \
    && (getent group desktop >/dev/null || groupadd -r desktop) \
    && (id desktop >/dev/null 2>&1 || useradd -m -s /bin/bash -r -g desktop -G audio,video desktop) \
    && chown -R desktop:desktop /workspace /home/desktop

COPY scripts/ta-open-browser /usr/local/bin/ta-open-browser
# arm64 镜像专用的 google-chrome shim 脚本（task #64）；amd64 build 时该文件
# COPY 进来但**不安装**（apt 包的 /usr/bin/google-chrome 已经存在，不能被 shim
# 覆盖），arm64 build 时由下方 RUN 段按架构安装到 /usr/local/bin/google-chrome。
COPY scripts/google-chrome /usr/local/share/turbo-agent-browser/google-chrome-shim
COPY applications/turbo-agent-browser.desktop /usr/share/applications/turbo-agent-browser.desktop
COPY xfce-helpers/turbo-agent-browser.desktop /usr/share/xfce4/helpers/turbo-agent-browser.desktop

# 浏览器命令链（task #64）：
# - amd64：apt 包 google-chrome-stable 自带 /usr/bin/google-chrome；
#   chromium / chromium-browser 软链指向同一二进制；不安装 shim。
# - arm64：playwright 自带 chromium 装在 /ms-playwright/chromium-*/；
#   shim 脚本安装到 /usr/local/bin/google-chrome（PATH 命中），chromium /
#   chromium-browser 软链指向 shim。
# sandbox service / ta-open-browser 启动器按 `for candidate in google-chrome
# chromium ...` 顺序探测，无论哪种架构第一项 google-chrome 命中，业务代码
# 不感知架构差异。
RUN chmod +x /usr/local/bin/ta-open-browser \
    && if [ "$TARGETARCH" = "amd64" ]; then \
          ln -sf /usr/bin/google-chrome /usr/local/bin/chromium \
          && ln -sf /usr/bin/google-chrome /usr/local/bin/chromium-browser \
          && update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/bin/google-chrome 100 ; \
       elif [ "$TARGETARCH" = "arm64" ]; then \
          install -m 0755 /usr/local/share/turbo-agent-browser/google-chrome-shim /usr/local/bin/google-chrome \
          && ln -sf /usr/local/bin/google-chrome /usr/local/bin/chromium \
          && ln -sf /usr/local/bin/google-chrome /usr/local/bin/chromium-browser \
          && update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/local/bin/google-chrome 100 ; \
       else \
          echo "task #64：本镜像仅支持 amd64 / arm64，当前 TARGETARCH=$TARGETARCH" >&2 ; \
          exit 1 ; \
       fi \
    && update-alternatives --install /usr/bin/editor editor /usr/bin/vim 80 \
    && update-alternatives --install /usr/bin/editor editor /usr/bin/nano 60 \
    && xdg-mime default turbo-agent-browser.desktop x-scheme-handler/http x-scheme-handler/https text/html || true \
    && mkdir -p /root/.config/xfce4 /home/desktop/.config/xfce4 /root/Desktop /home/desktop/Desktop \
    && printf 'WebBrowser=turbo-agent-browser\n' > /root/.config/xfce4/helpers.rc \
    && printf 'WebBrowser=turbo-agent-browser\n' > /home/desktop/.config/xfce4/helpers.rc \
    && cp /usr/share/applications/turbo-agent-browser.desktop /root/Desktop/turbo-agent-browser.desktop \
    && cp /usr/share/applications/turbo-agent-browser.desktop /home/desktop/Desktop/turbo-agent-browser.desktop \
    && chmod +x /root/Desktop/turbo-agent-browser.desktop /home/desktop/Desktop/turbo-agent-browser.desktop \
    # 光标尺寸放大（议题 #23）：
    # - Dockerfile 顶层 ENV XCURSOR_SIZE=32 已覆盖 X 客户端进程的默认值（X11 / 纯
    #   GTK 应用直接读 env）；但 XFCE 桌面环境启动后，xfsettingsd 会按
    #   xfconf-perchannel xsettings.xml 中 Gtk/CursorThemeSize 重设 GTK 光标大小，
    #   该值优先级高于 XCURSOR_SIZE。这里写一份 xsettings.xml 把 CursorThemeSize
    #   固化为 32，root + desktop 用户各一份。
    # - Net/IconThemeName / Net/ThemeName 留空（继承基础镜像默认），仅覆盖光标尺寸。
    && mkdir -p /root/.config/xfce4/xfconf/xfce-perchannel-xml \
        /home/desktop/.config/xfce4/xfconf/xfce-perchannel-xml \
    && printf '%s\n' \
        '<?xml version="1.0" encoding="UTF-8"?>' \
        '<channel name="xsettings" version="1.0">' \
        '  <property name="Gtk" type="empty">' \
        '    <property name="CursorThemeSize" type="int" value="32"/>' \
        '  </property>' \
        '</channel>' \
        > /root/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml \
    && cp /root/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml \
        /home/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml \
    && chown -R desktop:desktop /home/desktop

USER root
WORKDIR /workspace

CMD ["bash"]
