#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODULE_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BUILD_ROOT="$MODULE_ROOT/build"
DIST_DIR="$MODULE_ROOT/dist"
PYINSTALLER_BUILD="$BUILD_ROOT/pyinstaller"
PYINSTALLER_SPEC="$PYINSTALLER_BUILD/spec"
PYINSTALLER_WORK="$PYINSTALLER_BUILD/work"
VENV_DIR="$BUILD_ROOT/venv"

AGENT_BUILD_IMAGE="${AGENT_BUILD_IMAGE:-python:3.11-slim-bullseye}"
AGENT_BUILD_USE_DOCKER="${AGENT_BUILD_USE_DOCKER:-1}"
USED_DOCKER=0

run_host_build() {
  echo "[INFO] Using host Python environment for build" >&2
  rm -rf "$BUILD_ROOT" "$DIST_DIR"
  mkdir -p "$PYINSTALLER_BUILD" "$DIST_DIR"
  python3 -m venv --copies "$VENV_DIR"
  # shellcheck disable=SC1091
  source "$VENV_DIR/bin/activate"

  pip install --upgrade pip
  pip install .
  pip install "pyinstaller==6.6.0"

  pyinstaller \
    --clean \
    --onefile \
    --name argus-agent \
    --distpath "$DIST_DIR" \
    --workpath "$PYINSTALLER_WORK" \
    --specpath "$PYINSTALLER_SPEC" \
    --add-data "$MODULE_ROOT/pyproject.toml:." \
    "$MODULE_ROOT/entry.py"

  chmod +x "$DIST_DIR/argus-agent"
  deactivate
}

run_docker_build() {
  if ! command -v docker >/dev/null 2>&1; then
    echo "[ERROR] docker 命令不存在，无法在容器内构建。请安装 Docker 或设置 AGENT_BUILD_USE_DOCKER=0" >&2
    exit 1
  fi

  USED_DOCKER=1
  echo "[INFO] Building agent binary inside $AGENT_BUILD_IMAGE" >&2

  local host_uid host_gid
  host_uid="$(id -u)"
  host_gid="$(id -g)"
  docker_env=("--rm" "-v" "$MODULE_ROOT:/workspace" "-w" "/workspace" "--env" "TARGET_UID=${host_uid}" "--env" "TARGET_GID=${host_gid}")

  pass_env_if_set() {
    local var="$1"
    local value="${!var:-}"
    if [[ -n "$value" ]]; then
      docker_env+=("--env" "$var=$value")
    fi
  }

  pass_env_if_set PIP_INDEX_URL
  pass_env_if_set PIP_EXTRA_INDEX_URL
  pass_env_if_set PIP_TRUSTED_HOST
  pass_env_if_set HTTP_PROXY
  pass_env_if_set HTTPS_PROXY
  pass_env_if_set NO_PROXY
  pass_env_if_set http_proxy
  pass_env_if_set https_proxy
  pass_env_if_set no_proxy

build_script=$(cat <<'INNER'
set -euo pipefail
cd /workspace
apt-get update >/dev/null
apt-get install -y --no-install-recommends binutils >/dev/null
rm -rf /var/lib/apt/lists/*
rm -rf build dist
mkdir -p build/pyinstaller dist
python3 -m venv --copies build/venv
source build/venv/bin/activate
pip install --upgrade pip
pip install .
pip install pyinstaller==6.6.0
pyinstaller \
  --clean \
  --onefile \
  --name argus-agent \
  --distpath dist \
  --workpath build/pyinstaller/work \
  --specpath build/pyinstaller/spec \
  --add-data /workspace/pyproject.toml:. \
  entry.py
chmod +x dist/argus-agent

TARGET_UID="${TARGET_UID:-0}"
TARGET_GID="${TARGET_GID:-0}"
chown -R "$TARGET_UID:$TARGET_GID" dist build 2>/dev/null || true

python3 - <<'PY'
from pathlib import Path
from PyInstaller.archive.readers import CArchiveReader
import sys

archive = Path('dist/argus-agent')
out_dir = Path('build/compat_check')
out_dir.mkdir(parents=True, exist_ok=True)

major, minor = sys.version_info[:2]
libpython = f'libpython{major}.{minor}.so.1.0'
expected_libs = [
    libpython,
    'libssl.so.3',
    'libcrypto.so.3',
]
reader = CArchiveReader(str(archive))
extracted = []
missing = []
for name in expected_libs:
    try:
        data = reader.extract(name)
    except KeyError:
        missing.append(name)
        continue
    (out_dir / name).write_bytes(data)
    extracted.append(name)
(out_dir / 'manifest').write_text('\n'.join(extracted))
if extracted:
    print('[INFO] Extracted libraries: ' + ', '.join(extracted))
if missing:
    print('[WARN] Missing expected libraries in bundle: ' + ', '.join(missing))
PY

compat_check() {
  local lib_path="$1"
  if [[ ! -f "$lib_path" ]]; then
    echo "[WARN] Missing $lib_path for GLIBC check"
    return
  fi
  local max_glibc
  max_glibc=$(strings -a "$lib_path" | grep -Eo 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu | tail -n 1 || true)
  if [[ -n "$max_glibc" ]]; then
    echo "[INFO] $lib_path references up to $max_glibc"
  else
    echo "[INFO] $lib_path does not expose GLIBC version strings"
  fi
}

compat_libs=()
if [[ -f build/compat_check/manifest ]]; then
  mapfile -t compat_libs < build/compat_check/manifest
fi

if [[ ${#compat_libs[@]} -eq 0 ]]; then
  echo "[WARN] No libraries captured for GLIBC inspection"
else
  for lib in "${compat_libs[@]}"; do
    compat_check "build/compat_check/$lib"
  done
fi

deactivate
INNER
  )

  if ! docker run "${docker_env[@]}" "$AGENT_BUILD_IMAGE" bash -lc "$build_script"; then
    echo "[ERROR] Docker 构建失败，请检查 Docker 权限或设置 AGENT_BUILD_USE_DOCKER=0 在兼容主机上构建" >&2
    exit 1
  fi
}

if [[ "$AGENT_BUILD_USE_DOCKER" == "1" ]]; then
  run_docker_build
else
  run_host_build
fi

if [[ ! -f "$DIST_DIR/argus-agent" ]]; then
  echo "[ERROR] Agent binary was not produced" >&2
  exit 1
fi

if [[ "$USED_DOCKER" != "1" ]]; then
  if [[ ! -x "$VENV_DIR/bin/python" ]]; then
    echo "[WARN] PyInstaller virtualenv missing at $VENV_DIR; skipping compatibility check" >&2
  else
    COMPAT_DIR="$BUILD_ROOT/compat_check"
    rm -rf "$COMPAT_DIR"
    mkdir -p "$COMPAT_DIR"

    EXTRACT_SCRIPT=$(cat <<'PY'
from pathlib import Path
from PyInstaller.archive.readers import CArchiveReader
import sys

archive = Path('dist/argus-agent')
out_dir = Path('build/compat_check')
out_dir.mkdir(parents=True, exist_ok=True)

major, minor = sys.version_info[:2]
libpython = f'libpython{major}.{minor}.so.1.0'
expected_libs = [
    libpython,
    'libssl.so.3',
    'libcrypto.so.3',
]
reader = CArchiveReader(str(archive))
extracted = []
missing = []
for name in expected_libs:
    try:
        data = reader.extract(name)
    except KeyError:
        missing.append(name)
        continue
    (out_dir / name).write_bytes(data)
    extracted.append(name)
(out_dir / 'manifest').write_text('\n'.join(extracted))
if extracted:
    print('[INFO] Extracted libraries: ' + ', '.join(extracted))
if missing:
    print('[WARN] Missing expected libraries in bundle: ' + ', '.join(missing))
PY
)

    "$VENV_DIR/bin/python" - <<PY
$EXTRACT_SCRIPT
PY

    compat_libs=()
    if [[ -f "$COMPAT_DIR/manifest" ]]; then
      mapfile -t compat_libs < "$COMPAT_DIR/manifest"
    fi

    check_glibc_version() {
      local lib_path="$1"
      if [[ ! -f "$lib_path" ]]; then
        echo "[WARN] Skipping GLIBC check; file not found: $lib_path" >&2
        return
      fi
      if command -v strings >/dev/null 2>&1; then
        local max_glibc
        max_glibc=$(strings -a "$lib_path" | grep -Eo 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu | tail -n 1 || true)
        if [[ -n "$max_glibc" ]]; then
          echo "[INFO] $lib_path references up to $max_glibc"
        else
          echo "[INFO] $lib_path does not expose GLIBC version strings"
        fi
      else
        echo "[WARN] strings command unavailable; cannot inspect $lib_path" >&2
      fi
    }

    if [[ ${#compat_libs[@]} -eq 0 ]]; then
      echo "[WARN] No libraries captured for GLIBC inspection" >&2
    else
      for lib in "${compat_libs[@]}"; do
        check_glibc_version "$COMPAT_DIR/$lib"
      done
    fi
  fi
else
  echo "[INFO] Compatibility check executed inside container"
fi

echo "[INFO] Agent binary generated at $DIST_DIR/argus-agent"
