#!/usr/bin/env bash
# build-gtk4.sh — Compile and run native-hello using the GTK4 bridge on macOS.
#
# Usage:
#   ./build-gtk4.sh           # compile and run
#   ./build-gtk4.sh compile   # compile only
#   ./build-gtk4.sh clean     # remove build artefacts
#
# Requirements:
#   - elc in PATH (or ../../../lang/dist/platform/elc)
#   - clang (Xcode Command Line Tools)
#   - GTK4 via Homebrew: brew install gtk4
#   - macOS 12+
#
# This is the same pipeline as build.sh but targeting the GTK4 backend:
#   - Links with $(pkg-config --libs gtk4) instead of -framework Cocoa
#   - Compiles el_gtk4.c (plain C) instead of el_appkit.m (ObjC)
#   - Defines EL_TARGET_LINUX (the GTK4 target flag)
#
# Multi-file compilation strategy: see build.sh comments — identical rationale.

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-gtk4"

# 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

# GTK4 pkg-config flags
GTK4_CFLAGS=$(pkg-config --cflags gtk4)
GTK4_LIBS=$(pkg-config --libs gtk4)

CLANG_FLAGS_COMMON=(
    -std=c11
    -DEL_TARGET_LINUX
    -I "${EL_RUNTIME}"
)

clean() {
    rm -rf "${BUILD_DIR}"
    echo "Cleaned."
}

compile() {
    mkdir -p "${BUILD_DIR}"

    # ── 1. Vessel forward-declarations header ─────────────────────────────────
    # elc --emit-header emits full function bodies, not just prototypes.
    # Extract only the forward-declaration lines: stop at the first function
    # definition (a line that ends with ') {' opening a body block).
    # macOS awk does not support \s — use POSIX [[:space:]] instead.
    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}' \
        > "${BUILD_DIR}/el_native_vessel.h"

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

    # ── 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_gtk4.c (plain C, GTK4 backend) ─────────────────────────
    echo "==> Compiling el_gtk4.c (GTK4 bridge)..."
    # shellcheck disable=SC2086
    clang \
        -std=c11 \
        -DEL_TARGET_LINUX \
        -I "${EL_RUNTIME}" \
        ${GTK4_CFLAGS} \
        -c "${EL_RUNTIME}/el_gtk4.c" \
        -o "${BUILD_DIR}/el_gtk4.o"

    # ── 5a. Compile el_seed.c ─────────────────────────────────────────────────
    # el_seed.c provides the OS-boundary __-prefixed primitives + thin wrappers.
    # With -DEL_TARGET_LINUX, the EL_TARGET_LINUX section in el_seed.c is
    # compiled in (GTK4 forwarders) and the EL_TARGET_MACOS section is excluded.
    echo "==> Compiling el_seed.c (EL_TARGET_LINUX)..."
    # shellcheck disable=SC2086
    clang "${CLANG_FLAGS_COMMON[@]}" \
        ${GTK4_CFLAGS} \
        -c "${EL_RUNTIME}/el_seed.c" \
        -o "${BUILD_DIR}/el_seed.o"

    # ── 5b. Compile el_runtime.c and patch out duplicate __-prefixed symbols ──
    # Same strategy as build.sh: el_runtime.c has duplicates of the __-prefixed
    # OS wrappers that el_seed.c defines. Hide el_runtime.o's copies with nmedit.
    echo "==> Compiling el_runtime.c..."
    clang "${CLANG_FLAGS_COMMON[@]}" \
        -c "${EL_RUNTIME}/el_runtime.c" \
        -o "${BUILD_DIR}/el_runtime.o"

    echo "==> Patching el_runtime.o (hiding __-prefixed symbols duplicated in el_seed.o)..."
    nm "${BUILD_DIR}/el_seed.o" 2>/dev/null \
        | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.seed_T.txt"
    nm "${BUILD_DIR}/el_runtime.o" 2>/dev/null \
        | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.rt_T.txt"
    comm -23 "${BUILD_DIR}/.rt_T.txt" "${BUILD_DIR}/.seed_T.txt" \
        > "${BUILD_DIR}/.rt_keep.txt"
    nmedit -s "${BUILD_DIR}/.rt_keep.txt" "${BUILD_DIR}/el_runtime.o"

    # ── 6. Compile el-native vessel object ────────────────────────────────────
    # Vessel code calls __-prefixed builtins. el_native_target.h provides the
    # EL_TARGET_LINUX block of declarations (same function signatures as MACOS).
    echo "==> Compiling el-native vessel object..."
    clang "${CLANG_FLAGS_COMMON[@]}" \
        -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 (hiding vessel main)..."
    nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \
        | awk '/^[0-9a-f]+ T _/{print $3}' \
        | grep -v '^_main$' \
        > "${BUILD_DIR}/.vessel_keep.txt"
    nmedit -s "${BUILD_DIR}/.vessel_keep.txt" "${BUILD_DIR}/el_native_vessel.o"

    # ── 7. Compile app object ─────────────────────────────────────────────────
    # Inject el_native_target.h (float ops + EL_TARGET_LINUX native decls) and
    # the vessel's forward-declaration header.
    echo "==> Compiling app object..."
    clang "${CLANG_FLAGS_COMMON[@]}" \
        -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 ───────────────────────────────────────────────────────────────
    # el_seed.o        = OS-boundary primitives (__-prefixed) + GTK4 forwarders
    # el_runtime.o     = high-level builtins (str_len, json_*, etc.), patched
    # el_native_vessel.o = el-level widget API, patched
    # el_gtk4.o        = GTK4 C bridge
    # GTK4_LIBS        = $(pkg-config --libs gtk4)
    # -ldl             = dlsym for callback dispatch
    # -lpthread        = threading
    echo "==> Linking native-hello-gtk4..."
    # shellcheck disable=SC2086
    clang "${CLANG_FLAGS_COMMON[@]}" \
        "${BUILD_DIR}/native_hello.o" \
        "${BUILD_DIR}/el_native_vessel.o" \
        "${BUILD_DIR}/el_gtk4.o" \
        "${BUILD_DIR}/el_runtime.o" \
        "${BUILD_DIR}/el_seed.o" \
        ${GTK4_LIBS} \
        -ldl \
        -lpthread \
        -lcurl \
        -o "${BUILD_DIR}/native-hello-gtk4"

    echo "==> Build complete: ${BUILD_DIR}/native-hello-gtk4"
}

run() {
    compile
    echo "==> Launching native-hello-gtk4..."
    EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \
        "${BUILD_DIR}/native-hello-gtk4"
}

case "${1:-run}" in
    clean)   clean   ;;
    compile) compile ;;
    run|*)   run     ;;
esac
