#!/usr/bin/env bash
# ============================================================
# build_secure.sh — 用 Nuitka 把 lambdagent / agentpaas 编成原生 .so，
# 再重打包成「编译后 wheel」放进 dist-secure/。
#
# 与普通 wheel 的区别：解开 .whl 只有机器码 .so，没有 .py 源码。
# 产物是「平台 + Python 小版本」绑定的（如 cp311 + macOS arm64），
# 换架构/换 Python 小版本需在对应环境重新构建。
#
# 用法:  scripts/build_secure.sh [PYTHON]
#   PYTHON 默认 python3；必须是「原生架构 + 3.10+ + 带头文件」的解释器，
#   且该 Python 的版本即决定产出 wheel 的 cpXXX 标签。
#
# 前置:  C 编译器（macOS: xcode-select --install）
# ============================================================
set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_DIR"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info()  { echo -e "${BLUE}[INFO]${NC}  $1"; }
ok()    { echo -e "${GREEN}[OK]${NC}    $1"; }
warn()  { echo -e "${YELLOW}[WARN]${NC}  $1"; }
fail()  { echo -e "${RED}[FAIL]${NC}  $1"; exit 1; }

PYTHON="${1:-python3}"
command -v "$PYTHON" >/dev/null 2>&1 || fail "未找到 Python: $PYTHON"

# ── 架构/版本/头文件检查 ──────────────────────────────────
read -r PYVER PYARCH HAVE_H <<EOF
$("$PYTHON" - <<'PY'
import platform, sysconfig, os
inc = sysconfig.get_path('include')
print(f"{platform.python_version()} {platform.machine()} {int(os.path.exists(os.path.join(inc,'Python.h')))}")
PY
)
EOF
info "构建解释器: $PYTHON  (Python $PYVER, $PYARCH)"
HOSTARCH="$(uname -m)"
if [ "$PYARCH" != "$HOSTARCH" ]; then
    warn "Python 架构($PYARCH) ≠ 主机架构($HOSTARCH)。"
    warn "多半是 Rosetta 下的 x86_64 Python，会编出错架构的 .so。"
    warn "请改用原生 $HOSTARCH 的 Python（如 Homebrew 的 python3.11）。"
    fail "架构不匹配，已中止。"
fi
[ "$HAVE_H" = "1" ] || fail "缺 Python.h 头文件，无法编译。请装带头文件的 Python（如 Homebrew）。"

# ── 构建专用 venv（装 nuitka，不污染用户环境）──────────────
BUILD_VENV="$PROJECT_DIR/.nuitka-venv"
if [ ! -x "$BUILD_VENV/bin/python" ]; then
    info "创建构建环境 .nuitka-venv ..."
    "$PYTHON" -m venv "$BUILD_VENV"
fi
BPY="$BUILD_VENV/bin/python"
"$BPY" -m pip install -q --upgrade pip nuitka packaging wheel

# ── 1) 普通 wheel（保留正确的依赖元数据，repack 会复用）────
info "构建基准 wheel（取依赖元数据）..."
mkdir -p dist
rm -f dist/lambdagent-*.whl dist/agentpaas-*.whl
"$BPY" -m pip wheel --no-deps ./lambdagent -w dist/ --quiet
"$BPY" -m pip wheel --no-deps ./agentpaas  -w dist/ --quiet

# ── 2) Nuitka 编译两个包为整包 .so ────────────────────────
NOUT="$PROJECT_DIR/build_nuitka"
rm -rf "$NOUT"; mkdir -p "$NOUT"
COMMON_FLAGS=(--include-package-data=. --python-flag=no_docstrings --remove-output --assume-yes-for-downloads)

info "Nuitka 编译 lambdagent（可能数分钟）..."
"$BPY" -m nuitka --module lambdagent/src/lambdagent \
    --include-package=lambdagent --include-package-data=lambdagent \
    --python-flag=no_docstrings --remove-output --assume-yes-for-downloads \
    --output-dir="$NOUT"

info "Nuitka 编译 agentpaas（可能数分钟）..."
"$BPY" -m nuitka --module agentpaas/src/agentpaas \
    --include-package=agentpaas --include-package-data=agentpaas \
    --python-flag=no_docstrings --remove-output --assume-yes-for-downloads \
    --output-dir="$NOUT"

LG_SO=$(ls "$NOUT"/lambdagent.*.so 2>/dev/null | head -1)
AP_SO=$(ls "$NOUT"/agentpaas.*.so 2>/dev/null | head -1)
[ -f "$LG_SO" ] && [ -f "$AP_SO" ] || fail "未找到编译产物 .so"

# ── 3) 平台 tag ───────────────────────────────────────────
TAG=$("$BPY" -c "from packaging.tags import sys_tags; t=next(iter(sys_tags())); print(f'{t.interpreter}-{t.abi}-{t.platform}')")
info "目标 wheel 标签: $TAG"

# ── 4) 重打包成 .so wheel ─────────────────────────────────
mkdir -p dist-secure
rm -f dist-secure/lambdagent-*.whl dist-secure/agentpaas-*.whl
"$BPY" scripts/repack_wheel_so.py --wheel dist/lambdagent-*.whl --so "$LG_SO" --package lambdagent --tag "$TAG" --out dist-secure/
"$BPY" scripts/repack_wheel_so.py --wheel dist/agentpaas-*.whl  --so "$AP_SO" --package agentpaas  --tag "$TAG" --out dist-secure/

echo ""
ok "编译版 wheel 已生成 → dist-secure/"
for w in dist-secure/*.whl; do
    npy=$(unzip -l "$w" | grep -cE '\.py$'); nso=$(unzip -l "$w" | grep -cE '\.so$')
    echo "    $(basename "$w")   [.py=$npy  .so=$nso]"
done
echo ""
echo "  下一步: ./setup.sh --package   # 会优先用 dist-secure/ 里的编译 wheel 组装发行包"
echo ""
warn "提醒: 编译版 wheel 绑定 $TAG —— 用户的 Python 小版本与架构需匹配。"
warn "      逻辑已编成机器码不可反编译，但日志/prompt 等字符串常量仍可被 strings 提取（开源版 Nuitka 限制）。"
