#!/usr/bin/env bash
# ── scripts/fetch-libsodium.sh ──────────────────────────────────────────────
# Download and build libsodium from source for the target platform.
# Called automatically by CMake when the pre-built library is not found,
# or manually before building:
#
#   ./scripts/fetch-libsodium.sh              # native (Linux/macOS)
#   ./scripts/fetch-libsodium.sh --mac        # macOS cross-compile via osxcross
#   ./scripts/fetch-libsodium.sh --win        # Windows cross-compile via MinGW
#
# Output:  libs/libsodium/  (include/ + lib/libsodium.a)
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail

SODIUM_VERSION="1.0.18"
SODIUM_SHA256="6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1"
SODIUM_URL="https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-${SODIUM_VERSION}.tar.gz"

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

TARGET="native"
while [[ $# -gt 0 ]]; do
    case $1 in
        --mac)  TARGET="mac";  shift ;;
        --win)  TARGET="win";  shift ;;
        *)      echo "Unknown option: $1"; exit 1 ;;
    esac
done

# ── Output directories ──────────────────────────────────────────────────────
case "$TARGET" in
    mac) INSTALL_DIR="$PROJECT_DIR/libs/libsodium-mac" ;;
    win) INSTALL_DIR="$PROJECT_DIR/libs/libsodium-win" ;;
    *)   INSTALL_DIR="$PROJECT_DIR/libs/libsodium"     ;;
esac

# Skip if already built
if [[ -f "$INSTALL_DIR/lib/libsodium.a" ]]; then
    echo "[fetch-libsodium] Already present: $INSTALL_DIR/lib/libsodium.a"
    exit 0
fi

# ── Download ────────────────────────────────────────────────────────────────
TARBALL="$PROJECT_DIR/libs/libsodium-${SODIUM_VERSION}.tar.gz"
SRC_DIR="$PROJECT_DIR/libs/libsodium-${SODIUM_VERSION}"

if [[ ! -f "$TARBALL" ]]; then
    echo "[fetch-libsodium] Downloading libsodium ${SODIUM_VERSION}..."
    curl -fSL -o "$TARBALL" "$SODIUM_URL"
fi

# Verify checksum (sha256sum on Linux, shasum on macOS)
if command -v sha256sum &>/dev/null; then
    echo "$SODIUM_SHA256  $TARBALL" | sha256sum -c - || {
        echo "[fetch-libsodium] ERROR: SHA256 mismatch! Removing corrupted download."
        rm -f "$TARBALL"
        exit 1
    }
elif command -v shasum &>/dev/null; then
    echo "$SODIUM_SHA256  $TARBALL" | shasum -a 256 -c - || {
        echo "[fetch-libsodium] ERROR: SHA256 mismatch! Removing corrupted download."
        rm -f "$TARBALL"
        exit 1
    }
fi

# ── Extract ─────────────────────────────────────────────────────────────────
if [[ ! -d "$SRC_DIR" ]]; then
    echo "[fetch-libsodium] Extracting..."
    tar -xzf "$TARBALL" -C "$PROJECT_DIR/libs/"
fi

# ── Configure & build ───────────────────────────────────────────────────────
cd "$SRC_DIR"

CONFIGURE_ARGS=(
    --prefix="$INSTALL_DIR"
    --disable-shared
    --enable-static
    --with-pic
)

case "$TARGET" in
    mac)
        # Cross-compile for macOS via osxcross
        if [[ -z "${OSXCROSS:-}" ]]; then
            for try in "$PROJECT_DIR/external/osxcross" "$HOME/osxcross" "/opt/osxcross" "$PROJECT_DIR/osxcross"; do
                [[ -d "$try/target" ]] && OSXCROSS="$try" && break
            done
        fi
        if [[ -z "${OSXCROSS:-}" ]]; then
            echo "[fetch-libsodium] ERROR: osxcross not found. Set OSXCROSS=/path/to/osxcross"
            exit 1
        fi
        export PATH="$OSXCROSS/target/bin:$PATH"

        # Detect osxcross triple
        TRIPLE=$(ls "$OSXCROSS/target/bin/" | grep -o 'x86_64-apple-darwin[0-9]*' | head -1)
        [[ -z "$TRIPLE" ]] && TRIPLE="x86_64-apple-darwin22"

        CONFIGURE_ARGS+=(--host="$TRIPLE")
        export CC="${TRIPLE}-cc"
        export CXX="${TRIPLE}-c++"
        export AR="${TRIPLE}-ar"
        export RANLIB="${TRIPLE}-ranlib"
        ;;
    win)
        # Cross-compile for Windows via MinGW
        CONFIGURE_ARGS+=(--host=x86_64-w64-mingw32)
        # Prefer the posix-thread variant if available
        if command -v x86_64-w64-mingw32-gcc-posix &>/dev/null; then
            export CC=x86_64-w64-mingw32-gcc-posix
            export CXX=x86_64-w64-mingw32-g++-posix
        else
            export CC=x86_64-w64-mingw32-gcc
            export CXX=x86_64-w64-mingw32-g++
        fi
        export AR=x86_64-w64-mingw32-ar
        export RANLIB=x86_64-w64-mingw32-ranlib
        # Disable _FORTIFY_SOURCE — MinGW doesn't provide __memcpy_chk etc.
        export CFLAGS="${CFLAGS:-} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0"
        ;;
esac

# ── Native macOS: build universal binary (arm64 + x86_64) ───────────────────
IS_MACOS_NATIVE=false
if [[ "$TARGET" == "native" && "$(uname -s)" == "Darwin" ]]; then
    IS_MACOS_NATIVE=true
fi

if $IS_MACOS_NATIVE; then
    echo "[fetch-libsodium] Building universal (arm64 + x86_64) for macOS..."
    export MACOSX_DEPLOYMENT_TARGET="11.0"

    INSTALL_ARM64="$PROJECT_DIR/libs/libsodium-arm64"
    INSTALL_X86_64="$PROJECT_DIR/libs/libsodium-x86_64"

    for ARCH in arm64 x86_64; do
        echo "[fetch-libsodium] Building for $ARCH..."
        cd "$SRC_DIR"
        make clean 2>/dev/null || true
        make distclean 2>/dev/null || true

        if [[ "$ARCH" == "arm64" ]]; then
            ARCH_INSTALL="$INSTALL_ARM64"
            HOST_TRIPLE="aarch64-apple-darwin"
        else
            ARCH_INSTALL="$INSTALL_X86_64"
            HOST_TRIPLE="x86_64-apple-darwin"
        fi

        ARCH_CFLAGS="-arch $ARCH -mmacosx-version-min=11.0"

        ./configure \
            --prefix="$ARCH_INSTALL" \
            --disable-shared \
            --enable-static \
            --with-pic \
            --host="$HOST_TRIPLE" \
            CFLAGS="$ARCH_CFLAGS" \
            LDFLAGS="-arch $ARCH" \
            > /dev/null

        make -j"$(sysctl -n hw.ncpu 2>/dev/null || echo 4)" > /dev/null 2>&1
        make install > /dev/null
    done

    # Merge with lipo
    echo "[fetch-libsodium] Creating universal binary with lipo..."
    mkdir -p "$INSTALL_DIR/lib" "$INSTALL_DIR/include"
    lipo -create \
        "$INSTALL_ARM64/lib/libsodium.a" \
        "$INSTALL_X86_64/lib/libsodium.a" \
        -output "$INSTALL_DIR/lib/libsodium.a"
    cp -R "$INSTALL_ARM64/include/"* "$INSTALL_DIR/include/"

    # Clean up per-arch builds
    rm -rf "$INSTALL_ARM64" "$INSTALL_X86_64"
    cd "$PROJECT_DIR"
    rm -rf "$SRC_DIR"
    rm -f "$TARBALL"

    echo "[fetch-libsodium] Done (universal): $INSTALL_DIR/lib/libsodium.a"
    lipo -info "$INSTALL_DIR/lib/libsodium.a"
    exit 0
fi

echo "[fetch-libsodium] Configuring for target: $TARGET ..."
./configure "${CONFIGURE_ARGS[@]}" > /dev/null

echo "[fetch-libsodium] Building..."
make -j"$(nproc)" > /dev/null 2>&1

echo "[fetch-libsodium] Installing to $INSTALL_DIR ..."
make install > /dev/null

# ── Cleanup ─────────────────────────────────────────────────────────────────
cd "$PROJECT_DIR"
rm -rf "$SRC_DIR"
rm -f "$TARBALL"

echo "[fetch-libsodium] Done: $INSTALL_DIR/lib/libsodium.a"
