#!/bin/bash -eu
# SPDX-FileCopyrightText: 2025 Uwe Fechner
# SPDX-License-Identifier: MIT

update=false
if [[ $# -gt 0 ]]; then
    if [[ $1 != "--update" ]]; then
        echo "Invalid parameter! Use:"
        echo "./create_sys_image"
        echo "or"
        echo "./create_sys_image --update"
        exit 1
    else
        update=true
    fi
fi

if [[ $(basename $(pwd)) == "bin" ]]; then
    cd ..
fi

julia_version=$(julia --version | awk '{print($3)}')
julia_major=${julia_version:0:3} 
if [[ $julia_major == "1.1" ]]; then
    julia_major=${julia_version:0:4} 
fi
if test -f "kps-image-${julia_major}.so"; then
    mv bin/kps-image-${julia_major}.so kps-image-${julia_major}.so.bak
fi

if [[ $update == true ]]; then
    echo "Updating packages..."
    if test -f "Manifest.toml"; then
        mv Manifest.toml Manifest.toml.bak
    fi
    if test -f "Manifest-v1.10.toml"; then
        mv Manifest-v1.10.toml Manifest-v1.10.toml.bak
    fi
    if test -f "Manifest-v1.11.toml"; then
        mv Manifest-v1.11.toml Manifest-v1.11.toml.bak
    fi
    if test -f "Manifest-v1.12.toml"; then
        mv Manifest-v1.12.toml Manifest-v1.12.toml.bak
    fi
    julia --project -e "include(\"./test/update_packages.jl\");"
else
    echo "Using existing manifest file!"
fi
echo "Instantiating packages..."
# Instantiate packages first so artifacts are available for LD_PRELOAD setup
julia --startup-file=no --project -e "using Pkg; Pkg.instantiate();"

echo ". ./bin/setup_env"
# Load shared Julia environment setup (LD_PRELOAD, LD_LIBRARY_PATH, julia wrapper).
. ./bin/setup_env

# Run Pkg.precompile() and fail if either Julia exits non-zero or the output
# contains package-level precompile failure markers.
run_precompile() {
    local _proj="$1"
    local _plog
    _plog=$(mktemp)
    set +e
    julia --startup-file=no ${_proj} -e 'using Pkg; Pkg.precompile()' 2>&1 | tee "$_plog"
    _precompile_rc=${PIPESTATUS[0]}
    set -e
    if [[ $_precompile_rc -ne 0 ]] || \
       sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$_plog" | grep -qE "Failed to precompile|dependencies? errored"; then
        echo "ERROR: Precompilation failed for ${_proj}. See log above."
        rm -f "$_plog"
        exit 1
    fi
    rm -f "$_plog"
}

print_memory_snapshot() {
    echo "Memory snapshot:"
    if [[ "$(uname -s)" == "Linux" ]]; then
        awk '/MemTotal|MemAvailable|SwapTotal|SwapFree/ {printf "  %s %s %s\n", $1, $2, $3}' /proc/meminfo
        if [[ -r /sys/fs/cgroup/memory.max ]]; then
            local _cmax _ccur
            _cmax=$(cat /sys/fs/cgroup/memory.max 2>/dev/null || true)
            _ccur=$(cat /sys/fs/cgroup/memory.current 2>/dev/null || true)
            echo "  cgroup memory.max: ${_cmax:-unknown}"
            echo "  cgroup memory.current: ${_ccur:-unknown}"
        fi
    else
        echo "  Memory diagnostics are only implemented for Linux in this script."
    fi
}

# Check memory and limit threads if needed
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
    # Windows: use wmic or PowerShell
    echo "Checking system memory on Windows..."
    totalmem=$(powershell.exe -Command "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1MB" 2>/dev/null | awk '{printf "%i", $1}')
    if [[ -z "$totalmem" || $totalmem -lt 27000 ]]; then
        echo "Warning: Less than 27GB of memory detected on Windows. Using only one thread for sysimage compilation."
        export JULIA_IMAGE_THREADS=1
    fi
elif [[ "$OSTYPE" == darwin* ]]; then
    # macOS: use sysctl
    echo "Checking system memory on macOS..."
    totalmem=$(sysctl -n hw.memsize 2>/dev/null | awk '{printf "%i", $1 / 1000000}')
    if [[ -z "$totalmem" || $totalmem -lt 27000 ]]; then
        echo "Warning: Less than 27GB of memory detected on macOS. Using only one thread for sysimage compilation."
        export JULIA_IMAGE_THREADS=1
    fi
else
    # Linux: use /proc/meminfo
    totalmem=$(grep MemTotal /proc/meminfo | awk '{printf "%i", $2 / 1024}')
    if [[ $totalmem -lt 26674 ]]; then
        echo "Warning: Less than 27GB of memory detected. Using only one thread for sysimage compilation."
        export JULIA_IMAGE_THREADS=1
    fi
fi

echo "Precompiling packages.."
run_precompile "--project"
echo "Creating system image..."
print_memory_snapshot
set +e
julia --project -e "include(\"./test/create_sys_image.jl\");"
_sysimg_rc=$?
set -e
if [[ $_sysimg_rc -ne 0 ]]; then
    echo "ERROR: System image creation failed with exit code $_sysimg_rc"
    print_memory_snapshot
    if [[ $_sysimg_rc -eq 137 ]]; then
        echo "Hint: exit code 137 often indicates the process was killed by the OOM killer."
    else
        echo "Hint: enable detailed logs with: JULIA_DEBUG=PackageCompiler ./bin/create_sys_image2"
    fi
    exit $_sysimg_rc
fi
mv kps-image_tmp.so bin/kps-image-${julia_major}.so
run_precompile "--project"
