#!/usr/bin/env bash
# new-platform — scaffold a new el-native platform bridge
#
# Usage: ./new-platform <platform-name>
#
# Example:
#   ./new-platform myplatform
#
# Creates el_myplatform.c with all 33 required __* functions stubbed out,
# the ElWidget slot table, and the dlsym callback dispatcher.
#
# After running, follow the printed instructions to wire the bridge into
# el_native_target.h and el_seed.c.
#
# See PLATFORM_BRIDGE_SPEC.md for the full bridge contract.

set -euo pipefail

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

# ── Argument validation ───────────────────────────────────────────────────────

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <platform-name>" >&2
    echo "" >&2
    echo "  <platform-name>  lowercase identifier, e.g. myrtos, wayland, qt6" >&2
    echo "" >&2
    echo "This creates el_<platform-name>.c in the current directory." >&2
    exit 1
fi

PLATFORM_LOWER="${1,,}"   # force lowercase
PLATFORM_UPPER="${PLATFORM_LOWER^^}"   # force uppercase

# Validate: letters, digits, underscores only
if [[ ! "${PLATFORM_LOWER}" =~ ^[a-z][a-z0-9_]*$ ]]; then
    echo "Error: platform name must start with a letter and contain only a-z, 0-9, _" >&2
    exit 1
fi

OUTPUT_FILE="${SCRIPT_DIR}/el_${PLATFORM_LOWER}.c"

if [[ -f "${OUTPUT_FILE}" ]]; then
    echo "Error: ${OUTPUT_FILE} already exists." >&2
    echo "  Remove it first if you want to regenerate it." >&2
    exit 1
fi

# ── Generate the bridge file ──────────────────────────────────────────────────

cat > "${OUTPUT_FILE}" << BRIDGE_FILE
/*
 * el_${PLATFORM_LOWER}.c — el-native platform bridge for ${PLATFORM_UPPER}.
 *
 * Generated by new-platform. Replace the TODO stubs with real implementations.
 * See PLATFORM_BRIDGE_SPEC.md for the full contract.
 *
 * ── Slot system ──────────────────────────────────────────────────────────────
 * Every widget (window, button, label, container, image) is stored in a static
 * array of ElWidget structs. The el program holds an int64_t "handle" which is
 * a direct index into that array. Rules:
 *   - Slot 0 is NEVER valid. Scans start at index 1.
 *   - Handle -1 means "invalid" / "create failed".
 *   - Maximum 4096 concurrent widgets.
 *   - el_widget_get() returns NULL for 0, negative, out-of-range, or FREE slots.
 *
 * ── Callback ABI ─────────────────────────────────────────────────────────────
 * When a platform event fires (click, text change), call el_${PLATFORM_LOWER}_invoke_cb:
 *
 *   el_${PLATFORM_LOWER}_invoke_cb(w->cb_click, slot_index, "");
 *
 * The El callback signature:
 *   fn handler(handle: Int, data: String) -> Void
 * compiles to:
 *   void handler(int64_t handle, int64_t data)
 * where data is a const char* cast to int64_t (el String representation).
 *
 * ── Thread safety ────────────────────────────────────────────────────────────
 * ALL platform UI calls must run on the main/UI thread. If your platform
 * delivers events on background threads (e.g., from a network callback that
 * updates a label), marshal to the main thread before calling any widget op.
 *
 * ── Compile ──────────────────────────────────────────────────────────────────
 *   cc -DEL_TARGET_${PLATFORM_UPPER} \\
 *      \$(pkg-config --cflags <your-toolkit>) \\
 *      -c el_${PLATFORM_LOWER}.c -o el_${PLATFORM_LOWER}.o
 *
 * ── Link ─────────────────────────────────────────────────────────────────────
 *   cc el_${PLATFORM_LOWER}.o el_seed.o el_runtime.o -o myapp \\
 *      \$(pkg-config --libs <your-toolkit>) -ldl -lpthread
 */

#ifdef EL_TARGET_${PLATFORM_UPPER}

/* ── TODO: add platform-specific includes here ──────────────────────────────
 * Examples:
 *   #include <gtk/gtk.h>              // GTK4
 *   #include <SDL2/SDL.h>             // SDL2
 *   #include "lvgl/lvgl.h"            // LVGL
 *   #include <windows.h>              // Win32
 */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>   /* dlsym — replace with GetProcAddress on Windows */

/* ── Widget table ─────────────────────────────────────────────────────────── */

#define EL_${PLATFORM_UPPER}_MAX_WIDGETS 4096

typedef enum {
    EL_WIDGET_FREE      = 0,
    EL_WIDGET_WINDOW    = 1,
    EL_WIDGET_VSTACK    = 2,
    EL_WIDGET_HSTACK    = 3,
    EL_WIDGET_ZSTACK    = 4,
    EL_WIDGET_SCROLL    = 5,
    EL_WIDGET_LABEL     = 6,
    EL_WIDGET_BUTTON    = 7,
    EL_WIDGET_TEXTFIELD = 8,
    EL_WIDGET_TEXTAREA  = 9,
    EL_WIDGET_IMAGE     = 10,
} ElWidgetKind;

typedef struct {
    ElWidgetKind  kind;

    /* TODO: add your platform's native widget reference here.
     * Examples:
     *   GtkWidget*   widget;     // GTK4
     *   SDL_Rect     rect;       // SDL2 (no object, just geometry)
     *   lv_obj_t*    obj;        // LVGL
     *   HWND         hwnd;       // Win32
     *   void*        native;     // generic pointer
     */
    void*         native;   /* platform widget reference — replace as needed */

    /* Text content (cached for platforms that don't provide a get-text API) */
    char*         text;

    /* Foreground / background color (RGBA, 0.0-1.0) */
    float         fg_r, fg_g, fg_b, fg_a;
    float         bg_r, bg_g, bg_b, bg_a;

    /* Geometry */
    int           width;    /* 0 = not set */
    int           height;   /* 0 = not set */
    int           flex;     /* 0 = hug content, >0 = expand */

    /* Padding (top, right, bottom, left) */
    int           pad_top, pad_right, pad_bottom, pad_left;

    /* Corner radius */
    int           corner_radius;

    /* State */
    int           disabled; /* 0 = enabled, 1 = disabled */
    int           hidden;   /* 0 = visible, 1 = hidden */

    /* Event callbacks — El function name resolved at event time via dlsym */
    char*         cb_click;    /* on_click / on_submit */
    char*         cb_change;   /* on_change */
} ElWidget;

static ElWidget _el_widgets[EL_${PLATFORM_UPPER}_MAX_WIDGETS];

/* ── Slot management ──────────────────────────────────────────────────────── */

static int64_t el_widget_alloc(ElWidgetKind kind, void* native) {
    for (int i = 1; i < EL_${PLATFORM_UPPER}_MAX_WIDGETS; i++) {
        if (_el_widgets[i].kind == EL_WIDGET_FREE) {
            memset(&_el_widgets[i], 0, sizeof(ElWidget));
            _el_widgets[i].kind   = kind;
            _el_widgets[i].native = native;
            return (int64_t)i;
        }
    }
    fprintf(stderr, "el_${PLATFORM_LOWER}: widget table full (max %d)\n",
            EL_${PLATFORM_UPPER}_MAX_WIDGETS);
    return -1;
}

static ElWidget* el_widget_get(int64_t handle) {
    if (handle <= 0 || handle >= EL_${PLATFORM_UPPER}_MAX_WIDGETS) return NULL;
    if (_el_widgets[handle].kind == EL_WIDGET_FREE)               return NULL;
    return &_el_widgets[handle];
}

static void el_widget_free(int64_t handle) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: release w->native (toolkit-specific) */
    free(w->text);
    free(w->cb_click);
    free(w->cb_change);
    memset(w, 0, sizeof(ElWidget)); /* sets kind = EL_WIDGET_FREE (0) */
}

/* ── Callback dispatcher ─────────────────────────────────────────────────── */
/*
 * Invoke an El function by symbol name. The El function must have the
 * compiled signature:  void fn(int64_t handle, int64_t data)
 * where data is a const char* cast to int64_t (el String representation).
 *
 * On platforms without dlsym (e.g., Windows), replace with:
 *   GetProcAddress(GetModuleHandle(NULL), fn_name)
 * On embedded targets without dynamic linking, maintain a manual symbol table.
 */
typedef void (*ElCb2)(int64_t handle, int64_t data);

static void el_${PLATFORM_LOWER}_invoke_cb(const char* fn_name,
                                            int64_t handle,
                                            const char* data) {
    if (!fn_name || !*fn_name) return;
    void* sym = dlsym(RTLD_DEFAULT, fn_name);
    if (!sym) {
        fprintf(stderr, "el_${PLATFORM_LOWER}: callback symbol not found: %s\n", fn_name);
        return;
    }
    ElCb2 fn = (ElCb2)sym;
    fn(handle, (int64_t)(uintptr_t)(data ? data : ""));
}

/* ── Lifecycle ────────────────────────────────────────────────────────────── */

/*
 * el_${PLATFORM_LOWER}_init — initialize the platform toolkit.
 * Must be idempotent (safe to call more than once).
 * Called once from __native_init before any widget creation.
 */
void el_${PLATFORM_LOWER}_init(void) {
    static int done = 0;
    if (done) return;
    done = 1;

    /* TODO: initialize your platform toolkit here.
     * Examples:
     *   gtk_init(NULL, NULL);            // GTK4
     *   SDL_Init(SDL_INIT_VIDEO);        // SDL2
     *   lv_init();                       // LVGL
     */
}

/*
 * el_${PLATFORM_LOWER}_run_loop — start the platform event loop.
 * On most platforms this NEVER returns. Exceptions: Android (no-op).
 * Must be called from the main thread.
 */
void el_${PLATFORM_LOWER}_run_loop(void) {
    /* TODO: start the platform event/render loop.
     * Examples:
     *   gtk_main();                      // GTK4
     *   while (1) { SDL_PollEvent(...); render(); SDL_Delay(16); }  // SDL2
     *   while (1) { lv_task_handler(); usleep(5000); }              // LVGL
     */
}

/* ── Window ───────────────────────────────────────────────────────────────── */

int64_t el_${PLATFORM_LOWER}_window_create(const char* title, int w, int h,
                                            int mw, int mh) {
    /* TODO: create a top-level window.
     * title may be NULL — treat as "".
     * mw/mh are minimum dimensions (0 = no minimum).
     * Return slot handle on success, -1 on failure.
     */
    (void)title; (void)w; (void)h; (void)mw; (void)mh;
    return -1; /* TODO: implement */
}

void el_${PLATFORM_LOWER}_window_show(int64_t handle) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: make the window visible. */
}

void el_${PLATFORM_LOWER}_window_set_title(int64_t handle, const char* title) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: update the window title. title may be NULL — treat as "". */
    (void)title;
}

/* ── Layout containers ────────────────────────────────────────────────────── */

int64_t el_${PLATFORM_LOWER}_vstack_create(int spacing) {
    /* TODO: create a vertical linear container with the given spacing (px). */
    (void)spacing;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_hstack_create(int spacing) {
    /* TODO: create a horizontal linear container with the given spacing (px). */
    (void)spacing;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_zstack_create(void) {
    /* TODO: create a z-axis overlay container (children overlap). */
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_scroll_create(void) {
    /* TODO: create a scrollable container (vertical scroll, first child = content). */
    return -1; /* TODO: implement */
}

/* ── Leaf widgets ─────────────────────────────────────────────────────────── */

int64_t el_${PLATFORM_LOWER}_label_create(const char* text) {
    /* TODO: create a non-editable text label. text may be NULL — treat as "". */
    (void)text;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_button_create(const char* label) {
    /* TODO: create a clickable button with the given label text.
     * Wire up the platform event handler so on_click callbacks fire later. */
    (void)label;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_text_field_create(const char* placeholder) {
    /* TODO: create a single-line text input. placeholder may be NULL. */
    (void)placeholder;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_text_area_create(const char* placeholder) {
    /* TODO: create a multi-line text input (scrollable). placeholder may be NULL. */
    (void)placeholder;
    return -1; /* TODO: implement */
}

int64_t el_${PLATFORM_LOWER}_image_create(const char* path_or_name) {
    /* TODO: create an image widget.
     * Try path_or_name as a filesystem path first, then as a named resource.
     * If neither resolves, create an empty image widget (do not crash). */
    (void)path_or_name;
    return -1; /* TODO: implement */
}

/* ── Widget property setters ─────────────────────────────────────────────── */

void el_${PLATFORM_LOWER}_widget_set_text(int64_t handle, const char* text) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: update text on label, button, text field, text area, or window title.
     * Dispatch on w->kind. text may be NULL — treat as "".
     * Cache in w->text if the platform has no get-text API. */
    free(w->text);
    w->text = strdup(text ? text : "");
}

const char* el_${PLATFORM_LOWER}_widget_get_text(int64_t handle) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return "";
    /* TODO: return the current text of the widget.
     * If the platform provides a get-text API, use it.
     * Otherwise return w->text (populated by set_text).
     * NEVER return NULL — return "" on failure. */
    return w->text ? w->text : "";
}

void el_${PLATFORM_LOWER}_widget_set_color(int64_t handle,
                                            float r, float g, float b, float a) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->fg_r = r; w->fg_g = g; w->fg_b = b; w->fg_a = a;
    /* TODO: apply foreground (text) color to the platform widget. */
}

void el_${PLATFORM_LOWER}_widget_set_bg_color(int64_t handle,
                                               float r, float g, float b, float a) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->bg_r = r; w->bg_g = g; w->bg_b = b; w->bg_a = a;
    /* TODO: apply background color to the platform widget. */
}

void el_${PLATFORM_LOWER}_widget_set_font(int64_t handle,
                                           const char* family, int size, int bold) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: set font on text-bearing widgets (label, button, text field, text area).
     * family may be "system" — use the platform default font in that case.
     * Fall back to system font if family is not found. */
    (void)family; (void)size; (void)bold;
}

void el_${PLATFORM_LOWER}_widget_set_padding(int64_t handle,
                                              int top, int right,
                                              int bottom, int left) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->pad_top = top; w->pad_right = right;
    w->pad_bottom = bottom; w->pad_left = left;
    /* TODO: apply padding/insets to the platform container or text widget. */
}

void el_${PLATFORM_LOWER}_widget_set_width(int64_t handle, int width) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->width = width;
    /* TODO: apply a fixed-width constraint to the platform widget. */
}

void el_${PLATFORM_LOWER}_widget_set_height(int64_t handle, int height) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->height = height;
    /* TODO: apply a fixed-height constraint to the platform widget. */
}

void el_${PLATFORM_LOWER}_widget_set_flex(int64_t handle, int flex) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->flex = flex;
    /* TODO: set the flex/expand factor.
     * flex > 0 → widget expands to fill available space.
     * flex == 0 → widget hugs content size.
     * Maps to: content hugging priority (AppKit), hexpand/vexpand (GTK4),
     *          layout_weight (Android), stretch factor (SDL2 manual layout). */
}

void el_${PLATFORM_LOWER}_widget_set_corner_radius(int64_t handle, int radius) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->corner_radius = radius;
    /* TODO: apply rounded corners (requires GPU layer / backing surface on most platforms). */
}

void el_${PLATFORM_LOWER}_widget_set_disabled(int64_t handle, int disabled) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->disabled = disabled;
    /* TODO: enable or disable the widget (buttons, text fields). No-op for containers/labels. */
}

void el_${PLATFORM_LOWER}_widget_set_hidden(int64_t handle, int hidden) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    w->hidden = hidden;
    /* TODO: show or hide the widget.
     * hidden=1 → invisible but still occupies layout space (visibility:hidden semantics).
     * For windows: minimize or hide. */
}

/* ── Tree management ─────────────────────────────────────────────────────── */

void el_${PLATFORM_LOWER}_widget_add_child(int64_t parent, int64_t child) {
    ElWidget* pw = el_widget_get(parent);
    ElWidget* cw = el_widget_get(child);
    if (!pw || !cw) return;

    /* TODO: attach child to parent. Dispatch on pw->kind:
     *   EL_WIDGET_WINDOW  → add to root content view/container
     *   EL_WIDGET_VSTACK  → add as vertical child
     *   EL_WIDGET_HSTACK  → add as horizontal child
     *   EL_WIDGET_ZSTACK  → add as overlapping subview
     *   EL_WIDGET_SCROLL  → set as the scrollable content view (first child only)
     *   default           → add as plain subview
     * Do NOT add a window widget as a child. */
    (void)pw; (void)cw;
}

void el_${PLATFORM_LOWER}_widget_remove_child(int64_t parent, int64_t child) {
    ElWidget* pw = el_widget_get(parent);
    ElWidget* cw = el_widget_get(child);
    if (!pw || !cw) return;
    /* TODO: detach child from parent. The child slot remains allocated (not destroyed). */
    (void)pw; (void)cw;
}

void el_${PLATFORM_LOWER}_widget_destroy(int64_t handle) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    /* TODO: remove the widget from its parent/superview.
     * For windows: close the window.
     * Free any platform delegate/target objects stored in side tables.
     * Then free the slot: */
    el_widget_free(handle);
}

/* ── Event registration ───────────────────────────────────────────────────── */

void el_${PLATFORM_LOWER}_widget_on_click(int64_t handle, const char* fn_name) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    free(w->cb_click);
    w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL;
}

void el_${PLATFORM_LOWER}_widget_on_change(int64_t handle, const char* fn_name) {
    ElWidget* w = el_widget_get(handle);
    if (!w) return;
    free(w->cb_change);
    w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL;
}

void el_${PLATFORM_LOWER}_widget_on_submit(int64_t handle, const char* fn_name) {
    /* Submit (Enter key in text field) reuses the cb_click slot, matching AppKit convention. */
    el_${PLATFORM_LOWER}_widget_on_click(handle, fn_name);
}

/* ── Example event handler (adapt to your platform's callback mechanism) ─── */
/*
 * When a button is clicked in your platform event loop, call:
 *
 *   ElWidget* w = el_widget_get(slot_index);
 *   if (w && w->cb_click) {
 *       el_${PLATFORM_LOWER}_invoke_cb(w->cb_click, slot_index, "");
 *   }
 *
 * When a text field changes:
 *
 *   ElWidget* w = el_widget_get(slot_index);
 *   if (w && w->cb_change) {
 *       el_${PLATFORM_LOWER}_invoke_cb(w->cb_change, slot_index, current_text);
 *   }
 */

#endif /* EL_TARGET_${PLATFORM_UPPER} */
BRIDGE_FILE

chmod 644 "${OUTPUT_FILE}"

# ── Print next-steps instructions ────────────────────────────────────────────

UPPER="${PLATFORM_UPPER}"
LOWER="${PLATFORM_LOWER}"

cat << INSTRUCTIONS

Created: el_${LOWER}.c

Next steps:
  ────────────────────────────────────────────────────────────────────────────
  1. Add to el_native_target.h  (inside a new #ifdef EL_TARGET_${UPPER} block):

     #ifdef EL_TARGET_${UPPER}

     void      __native_init(void);
     void      __native_run_loop(void);

     el_val_t  __window_create(el_val_t title, el_val_t width, el_val_t height,
                                el_val_t min_width, el_val_t min_height);
     void      __window_show(el_val_t handle);
     void      __window_set_title(el_val_t handle, el_val_t title);

     el_val_t  __vstack_create(el_val_t spacing);
     el_val_t  __hstack_create(el_val_t spacing);
     el_val_t  __zstack_create(void);
     el_val_t  __scroll_create(void);

     el_val_t  __label_create(el_val_t text);
     el_val_t  __button_create(el_val_t label);
     el_val_t  __text_field_create(el_val_t placeholder);
     el_val_t  __text_area_create(el_val_t placeholder);
     el_val_t  __image_create(el_val_t path_or_name);

     void      __widget_set_text(el_val_t handle, el_val_t text);
     el_val_t  __widget_get_text(el_val_t handle);
     void      __widget_set_color(el_val_t handle, el_val_t r, el_val_t g,
                                   el_val_t b, el_val_t a);
     void      __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g,
                                      el_val_t b, el_val_t a);
     void      __widget_set_font(el_val_t handle, el_val_t family,
                                  el_val_t size, el_val_t bold);
     void      __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right,
                                     el_val_t bottom, el_val_t left);
     void      __widget_set_width(el_val_t handle, el_val_t width);
     void      __widget_set_height(el_val_t handle, el_val_t height);
     void      __widget_set_flex(el_val_t handle, el_val_t flex);
     void      __widget_set_corner_radius(el_val_t handle, el_val_t radius);
     void      __widget_set_disabled(el_val_t handle, el_val_t disabled);
     void      __widget_set_hidden(el_val_t handle, el_val_t hidden);

     void      __widget_add_child(el_val_t parent, el_val_t child);
     void      __widget_remove_child(el_val_t parent, el_val_t child);
     void      __widget_destroy(el_val_t handle);

     void      __widget_on_click(el_val_t handle, el_val_t fn_name);
     void      __widget_on_change(el_val_t handle, el_val_t fn_name);
     void      __widget_on_submit(el_val_t handle, el_val_t fn_name);

     el_val_t  __manifest_read(el_val_t path);

     #endif /* EL_TARGET_${UPPER} */

  ────────────────────────────────────────────────────────────────────────────
  2. Add to el_seed.c  (copy the EL_TARGET_MACOS block as a template and
     substitute el_appkit_ → el_${LOWER}_):

     #ifdef EL_TARGET_${UPPER}

     /* Forward declarations — implemented in el_${LOWER}.c */
     extern void    el_${LOWER}_init(void);
     extern void    el_${LOWER}_run_loop(void);
     extern int64_t el_${LOWER}_window_create(const char* title, int w, int h, int mw, int mh);
     extern void    el_${LOWER}_window_show(int64_t handle);
     extern void    el_${LOWER}_window_set_title(int64_t handle, const char* title);
     extern int64_t el_${LOWER}_vstack_create(int spacing);
     extern int64_t el_${LOWER}_hstack_create(int spacing);
     extern int64_t el_${LOWER}_zstack_create(void);
     extern int64_t el_${LOWER}_scroll_create(void);
     extern int64_t el_${LOWER}_label_create(const char* text);
     extern int64_t el_${LOWER}_button_create(const char* label);
     extern int64_t el_${LOWER}_text_field_create(const char* placeholder);
     extern int64_t el_${LOWER}_text_area_create(const char* placeholder);
     extern int64_t el_${LOWER}_image_create(const char* path_or_name);
     extern void    el_${LOWER}_widget_set_text(int64_t handle, const char* text);
     extern const char* el_${LOWER}_widget_get_text(int64_t handle);
     extern void    el_${LOWER}_widget_set_color(int64_t h, float r, float g, float b, float a);
     extern void    el_${LOWER}_widget_set_bg_color(int64_t h, float r, float g, float b, float a);
     extern void    el_${LOWER}_widget_set_font(int64_t h, const char* family, int size, int bold);
     extern void    el_${LOWER}_widget_set_padding(int64_t h, int top, int right, int bottom, int left);
     extern void    el_${LOWER}_widget_set_width(int64_t h, int width);
     extern void    el_${LOWER}_widget_set_height(int64_t h, int height);
     extern void    el_${LOWER}_widget_set_flex(int64_t h, int flex);
     extern void    el_${LOWER}_widget_set_corner_radius(int64_t h, int radius);
     extern void    el_${LOWER}_widget_set_disabled(int64_t h, int disabled);
     extern void    el_${LOWER}_widget_set_hidden(int64_t h, int hidden);
     extern void    el_${LOWER}_widget_add_child(int64_t parent, int64_t child);
     extern void    el_${LOWER}_widget_remove_child(int64_t parent, int64_t child);
     extern void    el_${LOWER}_widget_destroy(int64_t handle);
     extern void    el_${LOWER}_widget_on_click(int64_t h, const char* fn_name);
     extern void    el_${LOWER}_widget_on_change(int64_t h, const char* fn_name);
     extern void    el_${LOWER}_widget_on_submit(int64_t h, const char* fn_name);

     void __native_init(void)     { el_${LOWER}_init(); }
     void __native_run_loop(void) { el_${LOWER}_run_loop(); }

     el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height,
                               el_val_t min_width, el_val_t min_height) {
         return (el_val_t)el_${LOWER}_window_create(
             EL_CSTR(title),
             (int)(int64_t)width, (int)(int64_t)height,
             (int)(int64_t)min_width, (int)(int64_t)min_height);
     }
     void __window_show(el_val_t h)                  { el_${LOWER}_window_show((int64_t)h); }
     void __window_set_title(el_val_t h, el_val_t t) { el_${LOWER}_window_set_title((int64_t)h, EL_CSTR(t)); }

     el_val_t __vstack_create(el_val_t s)  { return (el_val_t)el_${LOWER}_vstack_create((int)(int64_t)s); }
     el_val_t __hstack_create(el_val_t s)  { return (el_val_t)el_${LOWER}_hstack_create((int)(int64_t)s); }
     el_val_t __zstack_create(void)         { return (el_val_t)el_${LOWER}_zstack_create(); }
     el_val_t __scroll_create(void)         { return (el_val_t)el_${LOWER}_scroll_create(); }

     el_val_t __label_create(el_val_t t)             { return (el_val_t)el_${LOWER}_label_create(EL_CSTR(t)); }
     el_val_t __button_create(el_val_t l)             { return (el_val_t)el_${LOWER}_button_create(EL_CSTR(l)); }
     el_val_t __text_field_create(el_val_t p)         { return (el_val_t)el_${LOWER}_text_field_create(EL_CSTR(p)); }
     el_val_t __text_area_create(el_val_t p)          { return (el_val_t)el_${LOWER}_text_area_create(EL_CSTR(p)); }
     el_val_t __image_create(el_val_t p)              { return (el_val_t)el_${LOWER}_image_create(EL_CSTR(p)); }

     void __widget_set_text(el_val_t h, el_val_t t)  { el_${LOWER}_widget_set_text((int64_t)h, EL_CSTR(t)); }
     el_val_t __widget_get_text(el_val_t h) {
         const char* s = el_${LOWER}_widget_get_text((int64_t)h);
         return EL_STR(s ? s : "");
     }
     void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) {
         el_${LOWER}_widget_set_color((int64_t)h,
             (float)el_to_float(r), (float)el_to_float(g),
             (float)el_to_float(b), (float)el_to_float(a));
     }
     void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) {
         el_${LOWER}_widget_set_bg_color((int64_t)h,
             (float)el_to_float(r), (float)el_to_float(g),
             (float)el_to_float(b), (float)el_to_float(a));
     }
     void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) {
         el_${LOWER}_widget_set_font((int64_t)h, EL_CSTR(family),
             (int)(int64_t)size, (int)(int64_t)bold);
     }
     void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right,
                                el_val_t bottom, el_val_t left) {
         el_${LOWER}_widget_set_padding((int64_t)h,
             (int)(int64_t)top, (int)(int64_t)right,
             (int)(int64_t)bottom, (int)(int64_t)left);
     }
     void __widget_set_width(el_val_t h, el_val_t w)          { el_${LOWER}_widget_set_width((int64_t)h, (int)(int64_t)w); }
     void __widget_set_height(el_val_t h, el_val_t ht)        { el_${LOWER}_widget_set_height((int64_t)h, (int)(int64_t)ht); }
     void __widget_set_flex(el_val_t h, el_val_t f)           { el_${LOWER}_widget_set_flex((int64_t)h, (int)(int64_t)f); }
     void __widget_set_corner_radius(el_val_t h, el_val_t r)  { el_${LOWER}_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); }
     void __widget_set_disabled(el_val_t h, el_val_t d)       { el_${LOWER}_widget_set_disabled((int64_t)h, (int)(int64_t)d); }
     void __widget_set_hidden(el_val_t h, el_val_t hid)       { el_${LOWER}_widget_set_hidden((int64_t)h, (int)(int64_t)hid); }
     void __widget_add_child(el_val_t p, el_val_t c)          { el_${LOWER}_widget_add_child((int64_t)p, (int64_t)c); }
     void __widget_remove_child(el_val_t p, el_val_t c)       { el_${LOWER}_widget_remove_child((int64_t)p, (int64_t)c); }
     void __widget_destroy(el_val_t h)                         { el_${LOWER}_widget_destroy((int64_t)h); }
     void __widget_on_click(el_val_t h, el_val_t fn)          { el_${LOWER}_widget_on_click((int64_t)h, EL_CSTR(fn)); }
     void __widget_on_change(el_val_t h, el_val_t fn)         { el_${LOWER}_widget_on_change((int64_t)h, EL_CSTR(fn)); }
     void __widget_on_submit(el_val_t h, el_val_t fn)         { el_${LOWER}_widget_on_submit((int64_t)h, EL_CSTR(fn)); }

     #endif /* EL_TARGET_${UPPER} */

  ────────────────────────────────────────────────────────────────────────────
  3. Implement each TODO in el_${LOWER}.c.

  4. Compile:
       cc -DEL_TARGET_${UPPER} -Wall \\
          \$(pkg-config --cflags <your-toolkit> 2>/dev/null) \\
          -c el_${LOWER}.c -o el_${LOWER}.o

  5. Link:
       cc el_${LOWER}.o el_seed.o el_runtime.o -o myapp \\
          \$(pkg-config --libs <your-toolkit> 2>/dev/null) \\
          -ldl -lpthread

  See PLATFORM_BRIDGE_SPEC.md for the full bridge contract and gotchas.
INSTRUCTIONS
