#!/usr/bin/env bash
# build-win32.sh — Cross-compile native-hello for Windows using mingw64.
#
# Requirements:
#   - x86_64-w64-mingw32-gcc (brew install mingw-w64)
#   - elc in PATH or at ../../../lang/dist/platform/elc
#
# Output: build-win32/native-hello.exe
#
# Note: We use el_runtime_win32.c instead of el_runtime.c / el_seed.c because
# those files have deep POSIX dependencies (pthread, curl, dlfcn, sys/socket,
# etc.) that cannot be cross-compiled to Windows. el_runtime_win32.c provides
# all the runtime symbols that native-hello and the el-native vessel actually
# call, using only standard C11 + Win32 APIs.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang"
EL_UI_ROOT="${SCRIPT_DIR}/../.."
EL_RUNTIME="${EL_LANG_ROOT}/runtime"
EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el"
BUILD_DIR="${SCRIPT_DIR}/build-win32"

# ── Locate elc ───────────────────────────────────────────────────────────────
if command -v elc &>/dev/null; then
    ELC="elc"
elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then
    ELC="${EL_LANG_ROOT}/dist/platform/elc"
else
    echo "Error: elc not found. Add it to PATH or place it at:"
    echo "  ${EL_LANG_ROOT}/dist/platform/elc"
    exit 1
fi

CC="x86_64-w64-mingw32-gcc"

# -D_WIN32_IE for SetWindowSubclass (comctl32 >= IE 0x0600)
CFLAGS=(
    -std=c11
    -DEL_TARGET_WIN32
    -D_WIN32_IE=0x0600
    -I"${EL_RUNTIME}"
    -Wall
    -Wno-unused-function
)

mkdir -p "${BUILD_DIR}"

# ── 1. Compile el-native vessel to C ─────────────────────────────────────────
echo "==> Compiling el-native vessel to C..."
"${ELC}" "${EL_NATIVE_VESSEL}" \
    > "${BUILD_DIR}/el_native_vessel.c"

# ── 2. Generate vessel header (declarations only) ────────────────────────────
# elc --emit-header includes function bodies AND bare global variable definitions.
# We extract only forward declarations with two awk passes:
#   Pass 1: stop before function bodies (same as macOS build.sh).
#   Pass 2: convert bare global variable definitions (^el_val_t NAME;) to
#           `extern el_val_t NAME;` so the app TU sees them as declarations,
#           not definitions — avoiding duplicate symbol errors at link time.
echo "==> Generating el-native vessel header (declarations only)..."
"${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \
    | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \
    | awk '/^el_val_t [A-Za-z_][A-Za-z0-9_]*;/{print "extern " $0; next} {print}' \
    > "${BUILD_DIR}/el_native_vessel.h"

# ── 3. Compile app entry to C ─────────────────────────────────────────────────
echo "==> Compiling app entry to C..."
EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \
    "${ELC}" "${SCRIPT_DIR}/src/main.el" \
    > "${BUILD_DIR}/native_hello.c"

# ── 4. Compile el_win32.c ─────────────────────────────────────────────────────
echo "==> Compiling el_win32.c (Win32 widget bridge)..."
${CC} "${CFLAGS[@]}" \
    -c "${EL_RUNTIME}/el_win32.c" \
    -o "${BUILD_DIR}/el_win32.o"

# ── 5. Compile el_runtime_win32.c ─────────────────────────────────────────────
# This replaces el_seed.c + el_runtime.c for Win32 targets.
echo "==> Compiling el_runtime_win32.c (Win32 runtime stub)..."
${CC} "${CFLAGS[@]}" \
    -c "${EL_RUNTIME}/el_runtime_win32.c" \
    -o "${BUILD_DIR}/el_runtime_win32.o"

# ── 6. Compile el-native vessel object ───────────────────────────────────────
echo "==> Compiling el-native vessel object..."
${CC} "${CFLAGS[@]}" \
    -include "${EL_RUNTIME}/el_native_target.h" \
    -c "${BUILD_DIR}/el_native_vessel.c" \
    -o "${BUILD_DIR}/el_native_vessel.o"

echo "==> Patching el_native_vessel.o (localising vessel main + shared globals)..."
# The vessel's compiled C has its own main(). We localize it so the linker sees
# only the app's main(). We also localize any globals (TOKEN_*, etc.) that the
# vessel defines but the app also declares — matching the nmedit step in
# build.sh (macOS), using objcopy for mingw.
VESSEL_LOCAL_SYMS=()
# Collect all defined (T and D/B/C) symbols in the vessel object
while IFS= read -r sym; do
    VESSEL_LOCAL_SYMS+=("--localize-symbol=${sym}")
done < <(x86_64-w64-mingw32-nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \
    | awk '/^[0-9a-f]+ [TDBCt] /{print $3}' \
    | grep -E '^(main|TOKEN_)' || true)
if [ ${#VESSEL_LOCAL_SYMS[@]} -gt 0 ]; then
    x86_64-w64-mingw32-objcopy "${VESSEL_LOCAL_SYMS[@]}" \
        "${BUILD_DIR}/el_native_vessel.o"
fi

# ── 7. Compile app object ─────────────────────────────────────────────────────
echo "==> Compiling app object..."
${CC} "${CFLAGS[@]}" \
    -include "${EL_RUNTIME}/el_native_target.h" \
    -include "${BUILD_DIR}/el_native_vessel.h" \
    -c "${BUILD_DIR}/native_hello.c" \
    -o "${BUILD_DIR}/native_hello.o"

# ── 8. Link ───────────────────────────────────────────────────────────────────
# -Wl,--export-all-symbols: make el callback functions (on_greet_click etc.)
#   visible to GetProcAddress(GetModuleHandle(NULL), fn_name) — the Win32
#   equivalent of POSIX dlsym(RTLD_DEFAULT, fn_name).
echo "==> Linking native-hello.exe..."
${CC} "${CFLAGS[@]}" \
    -Wl,--export-all-symbols \
    "${BUILD_DIR}/native_hello.o" \
    "${BUILD_DIR}/el_native_vessel.o" \
    "${BUILD_DIR}/el_win32.o" \
    "${BUILD_DIR}/el_runtime_win32.o" \
    -lcomctl32 -luser32 -lgdi32 -lkernel32 \
    -o "${BUILD_DIR}/native-hello.exe"

echo ""
echo "==> Built: ${BUILD_DIR}/native-hello.exe"
ls -lh "${BUILD_DIR}/native-hello.exe"
