#!/usr/bin/env bash
# 大龙虾沙箱镜像构建脚本（Linux / macOS / Git Bash）.
#
# 三段：docker build → pip 内省 → npm 内省 → 合并输出 installed-packages.json.
# pip 内省通过 bind mount introspect.py 跑，避开跨 shell 嵌套引号的坑.
#
# Windows 原生请用 build.ps1 / build.cmd.
set -euo pipefail

IMAGE_NAME="${IMAGE_NAME:-lobster-sandbox}"
IMAGE_TAG="${IMAGE_TAG:-py3.11-office-v4}"

HERE="$(cd "$(dirname "$0")" && pwd)"
CTX="$(cd "$HERE/.." && pwd)"
OUT_DIR="${OUT_DIR:-$HERE/out}"
mkdir -p "$OUT_DIR"

# ---- stage 政务字体到构建上下文 ----
# WEB-INF/fonts/ 是仓库已有的政务公文字体白名单（GB/T 9704-2012），Dockerfile COPY
# 需要从 context 读，所以 build 前临时拷到 $CTX/fonts/，build 结束（trap EXIT）清理.
FONTS_SRC="$(cd "$HERE/../../../fonts" && pwd)"
FONTS_STAGE="$CTX/fonts"
echo "staging fonts: $FONTS_SRC -> $FONTS_STAGE"
rm -rf "$FONTS_STAGE"
cp -r "$FONTS_SRC" "$FONTS_STAGE"
trap 'rm -rf "$FONTS_STAGE" && echo "cleaned up staged fonts: $FONTS_STAGE"' EXIT

echo "building ${IMAGE_NAME}:${IMAGE_TAG} (context=$CTX)"
# 用 --iidfile 把镜像 SHA 写到文件，不依赖 Docker Desktop 名字索引（已知会延迟/错乱）.
# 后续 re-tag 直接按 SHA 打 tag，100% 可靠——不管索引是什么状态.
IID_FILE="${OUT_DIR}/.last-build.iid"
rm -f "$IID_FILE"
docker build --iidfile "$IID_FILE" -t "${IMAGE_NAME}:${IMAGE_TAG}" -f "$HERE/Dockerfile" "$CTX"

# ---- hard verify + 兜底 re-tag 防 Docker Desktop 索引错乱 ----
# 已知现象：`docker build -t X:Y` 成功后，`docker image inspect X:Y` 偶尔返 "No such image".
# Tomcat 启动自检会走 inspect 路径，踩中就误判镜像不存在、code_exec 直接不可用.
# 修法：按 SHA 强制 re-tag，再 inspect 校验；失败直接 exit（不是 warning）.
echo "--- verifying image tag + hard re-tag ---"
if [ ! -s "$IID_FILE" ]; then
    echo "✗ expected iidfile not produced or empty: $IID_FILE" >&2
    exit 1
fi
IMAGE_SHA="$(cat "$IID_FILE" | tr -d '[:space:]')"  # 形如 sha256:abc...
echo "built image sha: $IMAGE_SHA"

if ! docker tag "$IMAGE_SHA" "${IMAGE_NAME}:${IMAGE_TAG}"; then
    echo "✗ docker tag $IMAGE_SHA ${IMAGE_NAME}:${IMAGE_TAG} failed" >&2
    exit 1
fi

VERIFY_SHA="$(docker image inspect "${IMAGE_NAME}:${IMAGE_TAG}" --format '{{.Id}}' 2>&1)" || {
    echo "✗ docker image inspect failed after re-tag: $VERIFY_SHA" >&2
    echo "  Docker Desktop image index may be corrupt. Restart Docker Desktop, then re-run build.sh." >&2
    exit 1
}
echo "verified: ${IMAGE_NAME}:${IMAGE_TAG} -> $VERIFY_SHA"

echo "--- introspecting pip packages ---"
INTROSPECT_PY="$HERE/introspect.py"
if [ ! -f "$INTROSPECT_PY" ]; then
    echo "introspect.py not found at $INTROSPECT_PY" >&2
    exit 1
fi
PIP_JSON="$(docker run --rm \
    -v "${INTROSPECT_PY}:/tmp/introspect.py:ro" \
    --entrypoint python \
    "${IMAGE_NAME}:${IMAGE_TAG}" \
    /tmp/introspect.py)"

echo "--- introspecting npm globals ---"
NPM_JSON="$(docker run --rm --entrypoint npm "${IMAGE_NAME}:${IMAGE_TAG}" ls -g --depth=0 --json 2>/dev/null || true)"

# 合并成 installed-packages.json
python3 - <<PY > "${OUT_DIR}/installed-packages.json"
import json, sys
pip = json.loads('''${PIP_JSON}''') if '''${PIP_JSON}'''.strip() else []
try:
    npm_obj = json.loads('''${NPM_JSON}''') if '''${NPM_JSON}'''.strip() else {}
    npm = sorted(list((npm_obj.get("dependencies") or {}).keys()))
except Exception:
    npm = []
print(json.dumps({
    "image": "${IMAGE_NAME}:${IMAGE_TAG}",
    "packages": pip,
    "npm": npm,
}, indent=2))
PY

echo ""
echo "built ${IMAGE_NAME}:${IMAGE_TAG}"
echo "pip packages: $(python3 -c "import json; print(len(json.loads(open('${OUT_DIR}/installed-packages.json').read())['packages']))") entries"
echo "npm packages: $(python3 -c "import json; print(len(json.loads(open('${OUT_DIR}/installed-packages.json').read())['npm']))") entries"
echo "white-list written to ${OUT_DIR}/installed-packages.json"
echo ""
echo "Next: copy ${OUT_DIR}/installed-packages.json to <webapp>/WEB-INF/sandbox-installed-packages.json"
