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

# Build universal native dependencies (better-sqlite3 + sqlite-vec) for the packaged bundle.
# Relies on the universal Node runtime prepared in dist/runtime/node-universal.

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

export PATH="$REPO_ROOT/scripts:$PATH"

DIST_ROOT="${DIST_ROOT:-$REPO_ROOT/dist/local-app}"
APP_DIR="${APP_DIR:-$DIST_ROOT/app}"
NODE_RUNTIME_DIR="${NODE_RUNTIME_DIR:-$REPO_ROOT/dist/runtime/node-universal}"
NODE_BIN="$NODE_RUNTIME_DIR/bin/node"
NPM_CLI="$NODE_RUNTIME_DIR/lib/node_modules/npm/bin/npm-cli.js"

SQLITE_VEC_REPO="${SQLITE_VEC_REPO:-https://github.com/asg017/sqlite-vec.git}"
SQLITE_VEC_REF="${SQLITE_VEC_REF:-main}"
SQLITE_VEC_SOURCE_DIR="${SQLITE_VEC_SOURCE_DIR:-$REPO_ROOT/dist/.deps/sqlite-vec-src}"
SQLITE_VEC_OUTPUT="${SQLITE_VEC_OUTPUT:-$DIST_ROOT/vendor/sqlite-extensions/vec0.dylib}"
SQLITE_VEC_VENDOR_COPY="${SQLITE_VEC_VENDOR_COPY:-$REPO_ROOT/vendor/sqlite-extensions/vec0.dylib}"

TMP_DIR="$(mktemp -d -t rah-native-XXXX)"
cleanup() {
  rm -rf "$TMP_DIR"
}
trap cleanup EXIT

ensure_prerequisites() {
  if [ ! -x "$NODE_BIN" ]; then
    echo "❌ Universal Node runtime missing at $NODE_BIN" >&2
    echo "   Run scripts/build-universal-node.sh first." >&2
    exit 1
  fi

  if [ ! -d "$APP_DIR" ]; then
    echo "❌ Next.js standalone output missing at $APP_DIR" >&2
    echo "   Ensure scripts/build-production.sh has copied the app bundle." >&2
    exit 1
  fi

  if [ ! -d "$APP_DIR/node_modules/better-sqlite3" ]; then
    echo "❌ better-sqlite3 node module missing from $APP_DIR/node_modules." >&2
    echo "   Did you run npm run build before invoking this script?" >&2
    exit 1
  fi

  if ! command -v arch >/dev/null 2>&1; then
    echo "❌ arch command not found. Install Xcode command line tools." >&2
    exit 1
  fi

  if arch -x86_64 /usr/bin/true >/dev/null 2>&1; then
    :
  else
    echo "❌ Rosetta is required to build x86_64 binaries. Install with 'softwareupdate --install-rosetta'." >&2
    exit 1
  fi

  if ! command -v lipo >/dev/null 2>&1; then
    echo "❌ lipo not found. Install Xcode command line tools (xcode-select --install)." >&2
    exit 1
  fi

  if ! command -v git >/dev/null 2>&1; then
    echo "❌ git not found. Install git to fetch sqlite-vec source." >&2
    exit 1
  fi
}

ensure_sqlite_vec_source() {
  if [ -d "$SQLITE_VEC_SOURCE_DIR/.git" ]; then
    return
  fi

  echo "⬇️  Cloning sqlite-vec sources into $SQLITE_VEC_SOURCE_DIR"
  mkdir -p "$(dirname "$SQLITE_VEC_SOURCE_DIR")"
  git clone --depth 1 --branch "$SQLITE_VEC_REF" "$SQLITE_VEC_REPO" "$SQLITE_VEC_SOURCE_DIR"
}

refresh_better_sqlite3_sources() {
  local root_module="$REPO_ROOT/node_modules/better-sqlite3"
  local target_module="$APP_DIR/node_modules/better-sqlite3"

  if [ ! -d "$root_module" ]; then
    echo "❌ Root better-sqlite3 module missing at $root_module" >&2
    echo "   Run npm install in the repo root before packaging." >&2
    exit 1
  fi

  rm -rf "$target_module"
  mkdir -p "$target_module"
  rsync -a "$root_module/" "$target_module/"
}

arch_prefix() {
  local arch="$1"
  if [ "$arch" = "x86_64" ]; then
    echo "arch -x86_64"
  else
    echo "arch -arm64"
  fi
}

codesign_if_available() {
  local target="$1"
  if ! command -v codesign >/dev/null 2>&1; then
    return
  fi

  local identity="${CODESIGN_IDENTITY:--}"
  local extra_opts=()
  if [ "${CODESIGN_HARDENED_RUNTIME:-1}" = "1" ]; then
    extra_opts=(--options runtime)
  fi

  local codesign_cmd=(codesign --force --timestamp --sign "$identity" "${extra_opts[@]}" "$target")

  "${codesign_cmd[@]}" >/dev/null 2>&1 || \
    codesign --force --timestamp --sign - "${extra_opts[@]}" "$target" >/dev/null 2>&1 || true
}

rebuild_better_sqlite3_for_arch() {
  local arch="$1"
  local output="$TMP_DIR/better_sqlite3.${arch}.node"

  echo "⚙️  Rebuilding better-sqlite3 for ${arch}"

  rm -rf "$APP_DIR/node_modules/better-sqlite3/build"

  local arch_cmd
  arch_cmd=($(arch_prefix "$arch"))

  (
    cd "$APP_DIR"
    PATH="$NODE_RUNTIME_DIR/bin:$PATH" \
    npm_config_build_from_source=true \
    npm_config_fallback_to_build=false \
    npm_config_arch="$arch" \
    npm_config_target_arch="$arch" \
    CFLAGS="-arch $arch" \
    CXXFLAGS="-arch $arch" \
    LDFLAGS="-arch $arch" \
    "${arch_cmd[@]}" "$NODE_BIN" "$NPM_CLI" rebuild better-sqlite3 --build-from-source
  )

  if [ ! -f "$APP_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node" ]; then
    echo "❌ Failed to build better-sqlite3 for ${arch}" >&2
    exit 1
  fi

  cp "$APP_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node" "$output"
}

combine_better_sqlite3() {
  local arm_file="$TMP_DIR/better_sqlite3.arm64.node"
  local x64_file="$TMP_DIR/better_sqlite3.x86_64.node"
  local target="$APP_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node"

  lipo -create "$arm_file" "$x64_file" -output "$target"
  codesign_if_available "$target"
  rm -f "$APP_DIR/node_modules/better-sqlite3/build/Release/test_extension.node"
  echo "✓ better-sqlite3 universal binary ready at $target"
}

build_sqlite_vec_for_arch() {
  local arch="$1"
  local output="$TMP_DIR/vec0.${arch}.dylib"

  echo "⚙️  Building sqlite-vec (vec0) for ${arch}"

  local include_dir="${SQLITE3_INCLUDE_DIR:-}"
  local lib_dir="${SQLITE3_LIB_DIR:-}"

  if { [ -z "$include_dir" ] || [ -z "$lib_dir" ]; } && command -v brew >/dev/null 2>&1; then
    local brew_prefix
    brew_prefix="$(brew --prefix sqlite 2>/dev/null || true)"
    if [ -n "$brew_prefix" ]; then
      if [ -z "$include_dir" ] && [ -d "$brew_prefix/include" ]; then
        include_dir="$brew_prefix/include"
      fi
      if [ -z "$lib_dir" ] && [ -d "$brew_prefix/lib" ]; then
        lib_dir="$brew_prefix/lib"
      fi
    fi
  fi

  local cflags="-O3 -fPIC -arch $arch -undefined dynamic_lookup"
  if [ -n "$include_dir" ]; then
    cflags="$cflags -I${include_dir}"
  fi
  if [ -n "$lib_dir" ]; then
    cflags="$cflags -L${lib_dir}"
  fi

  local arch_cmd
  arch_cmd=($(arch_prefix "$arch"))

  local -a env_vars=(
    "CC=clang"
    "CFLAGS=$cflags"
  )

  if [ -n "$include_dir" ] || [ -n "$lib_dir" ]; then
    env_vars+=("USE_BREW_SQLITE=1")
    if [ -n "$include_dir" ]; then
      env_vars+=("SQLITE_INCLUDE_PATH=-I${include_dir}")
    fi
    if [ -n "$lib_dir" ]; then
      env_vars+=("SQLITE_LIB_PATH=-L${lib_dir}")
    fi
  fi

  (
    cd "$SQLITE_VEC_SOURCE_DIR"
    make clean >/dev/null 2>&1 || true
    "${arch_cmd[@]}" env "${env_vars[@]}" make loadable
  )

  local built_path="$SQLITE_VEC_SOURCE_DIR/dist/vec0.dylib"

  if [ ! -f "$built_path" ]; then
    echo "❌ sqlite-vec build failed for ${arch}. Inspect make output above." >&2
    exit 1
  fi

  mv "$built_path" "$output"
}

combine_sqlite_vec() {
  mkdir -p "$(dirname "$SQLITE_VEC_OUTPUT")"
  mkdir -p "$(dirname "$SQLITE_VEC_VENDOR_COPY")"

  lipo -create \
    "$TMP_DIR/vec0.arm64.dylib" \
    "$TMP_DIR/vec0.x86_64.dylib" \
    -output "$SQLITE_VEC_OUTPUT"

  cp "$SQLITE_VEC_OUTPUT" "$SQLITE_VEC_VENDOR_COPY"

  codesign_if_available "$SQLITE_VEC_OUTPUT"
  codesign_if_available "$SQLITE_VEC_VENDOR_COPY"

  echo "✓ sqlite-vec universal dylib ready at $SQLITE_VEC_OUTPUT"
}

codesign_additional_binaries() {
  local -a extras=(
    "$DIST_ROOT/bin/yt-dlp"
    "$APP_DIR/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node"
    "$APP_DIR/node_modules/@img/sharp-darwin-x64/lib/sharp-darwin-x64.node"
  )

  for target in "${extras[@]}"; do
    if [ -e "$target" ]; then
      codesign_if_available "$target"
    fi
  done

  local glob
  for glob in \
    "$APP_DIR/node_modules/@img/sharp-libvips-darwin-arm64/lib/"* \
    "$APP_DIR/node_modules/@img/sharp-libvips-darwin-x64/lib/"*; do
    if [ -e "$glob" ]; then
      codesign_if_available "$glob"
    fi
  done
}

main() {
  ensure_prerequisites
  ensure_sqlite_vec_source
  refresh_better_sqlite3_sources

  rebuild_better_sqlite3_for_arch arm64
  rebuild_better_sqlite3_for_arch x86_64
  combine_better_sqlite3

  build_sqlite_vec_for_arch arm64
  build_sqlite_vec_for_arch x86_64
  combine_sqlite_vec
  codesign_additional_binaries
}

main "$@"
