#ifndef NATIVE_SDK_APPKIT_HOST_H
#define NATIVE_SDK_APPKIT_HOST_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct native_sdk_appkit_host native_sdk_appkit_host_t;

typedef enum {
    NATIVE_SDK_APPKIT_EVENT_START = 0,
    NATIVE_SDK_APPKIT_EVENT_FRAME = 1,
    NATIVE_SDK_APPKIT_EVENT_SHUTDOWN = 2,
    NATIVE_SDK_APPKIT_EVENT_RESIZE = 3,
    NATIVE_SDK_APPKIT_EVENT_WINDOW_FRAME = 4,
    NATIVE_SDK_APPKIT_EVENT_SHORTCUT = 5,
    NATIVE_SDK_APPKIT_EVENT_NATIVE_COMMAND = 6,
    NATIVE_SDK_APPKIT_EVENT_MENU_COMMAND = 7,
    NATIVE_SDK_APPKIT_EVENT_APP_ACTIVATED = 8,
    NATIVE_SDK_APPKIT_EVENT_APP_DEACTIVATED = 9,
    NATIVE_SDK_APPKIT_EVENT_FILES_DROPPED = 10,
    NATIVE_SDK_APPKIT_EVENT_GPU_SURFACE_FRAME = 11,
    NATIVE_SDK_APPKIT_EVENT_GPU_SURFACE_RESIZE = 12,
    NATIVE_SDK_APPKIT_EVENT_GPU_SURFACE_INPUT = 13,
    NATIVE_SDK_APPKIT_EVENT_WIDGET_ACCESSIBILITY_ACTION = 14,
    NATIVE_SDK_APPKIT_EVENT_APPEARANCE_CHANGED = 15,
    NATIVE_SDK_APPKIT_EVENT_TIMER = 16,
    NATIVE_SDK_APPKIT_EVENT_WAKE = 17,
    NATIVE_SDK_APPKIT_EVENT_GPU_SURFACE_SCROLL_DRIVER = 18,
    NATIVE_SDK_APPKIT_EVENT_CONTEXT_MENU_ACTION = 19,
    NATIVE_SDK_APPKIT_EVENT_AUDIO = 20,
    NATIVE_SDK_APPKIT_EVENT_VIDEO = 21,
    NATIVE_SDK_APPKIT_EVENT_VIEW_FOCUSED = 22,
    NATIVE_SDK_APPKIT_EVENT_TRAY_COMMAND = 23,
    NATIVE_SDK_APPKIT_EVENT_NOTIFICATION_COMMAND = 24,
} native_sdk_appkit_event_kind_t;

/* Audio player reports (EVENT_AUDIO payloads). LOADED acknowledges a
 * successful native_sdk_appkit_audio_load (or a ready URL stream) with
 * the decoded duration; POSITION ticks at a coarse honest cadence
 * (~500ms) only while playing; COMPLETED fires exactly once at a
 * track's natural end; FAILED reports an asynchronous decode/device
 * failure — or a network failure that killed a stream mid-flight.
 * SPECTRUM carries a real band-magnitude analysis of the audio the
 * player is producing (audio_bands below) at a steady ~25 Hz, only
 * while audio is audibly playing — pause, stop, and a buffering stall
 * starve it. Ordinals are mirrored by the Zig side
 * (audioEventKindFromInt). */
typedef enum {
    NATIVE_SDK_APPKIT_AUDIO_EVENT_LOADED = 0,
    NATIVE_SDK_APPKIT_AUDIO_EVENT_POSITION = 1,
    NATIVE_SDK_APPKIT_AUDIO_EVENT_COMPLETED = 2,
    NATIVE_SDK_APPKIT_AUDIO_EVENT_FAILED = 3,
    NATIVE_SDK_APPKIT_AUDIO_EVENT_SPECTRUM = 4,
} native_sdk_appkit_audio_event_kind_t;

/* Video player reports (EVENT_VIDEO payloads). LOADED acknowledges a
 * successful native_sdk_appkit_video_load (or a ready URL stream) with
 * the stream's true pixel dimensions and the decoded duration; POSITION
 * ticks at a coarse honest cadence (~500ms) only while playing;
 * COMPLETED fires exactly once at a non-looping video's natural end (a
 * looping playback wraps and never completes); FAILED reports an
 * asynchronous decode/device failure — or a network failure that killed
 * a stream mid-flight. Pixels never ride events: decoded frames flow
 * through the sink push handed to the load entries. Ordinals are
 * mirrored by the Zig side (videoEventKindFromInt). */
typedef enum {
    NATIVE_SDK_APPKIT_VIDEO_EVENT_LOADED = 0,
    NATIVE_SDK_APPKIT_VIDEO_EVENT_POSITION = 1,
    NATIVE_SDK_APPKIT_VIDEO_EVENT_COMPLETED = 2,
    NATIVE_SDK_APPKIT_VIDEO_EVENT_FAILED = 3,
} native_sdk_appkit_video_event_kind_t;

/* How many band magnitudes every SPECTRUM report carries: 32 buckets
 * with log-spaced center frequencies covering roughly 50 Hz..16 kHz.
 * Part of the event ABI — the Zig side binds the array by this count. */
#define NATIVE_SDK_APPKIT_AUDIO_SPECTRUM_BANDS 32

typedef enum {
    NATIVE_SDK_APPKIT_COLOR_SCHEME_LIGHT = 0,
    NATIVE_SDK_APPKIT_COLOR_SCHEME_DARK = 1,
} native_sdk_appkit_color_scheme_t;

typedef enum {
    NATIVE_SDK_APPKIT_GPU_INPUT_POINTER_DOWN = 0,
    NATIVE_SDK_APPKIT_GPU_INPUT_POINTER_UP = 1,
    NATIVE_SDK_APPKIT_GPU_INPUT_POINTER_MOVE = 2,
    NATIVE_SDK_APPKIT_GPU_INPUT_POINTER_DRAG = 3,
    NATIVE_SDK_APPKIT_GPU_INPUT_SCROLL = 4,
    NATIVE_SDK_APPKIT_GPU_INPUT_KEY_DOWN = 5,
    NATIVE_SDK_APPKIT_GPU_INPUT_KEY_UP = 6,
    NATIVE_SDK_APPKIT_GPU_INPUT_TEXT_INPUT = 7,
    NATIVE_SDK_APPKIT_GPU_INPUT_IME_SET_COMPOSITION = 8,
    NATIVE_SDK_APPKIT_GPU_INPUT_IME_COMMIT_COMPOSITION = 9,
    NATIVE_SDK_APPKIT_GPU_INPUT_IME_CANCEL_COMPOSITION = 10,
    NATIVE_SDK_APPKIT_GPU_INPUT_POINTER_CANCEL = 11,
    /* Trackpad pinch phases (magnifyWithEvent:). The event's `scale`
     * field carries the per-event magnification DELTA on PINCH_CHANGE —
     * raw NSEvent.magnification, which IS the multiplicative per-event
     * delta per the browser-engine convention (see the doctrine note at
     * magnifyWithEvent: in appkit_host.m); cumulative gesture scale is
     * the product of (1 + delta); 0 on begin/end. The pointer anchor rides
     * x/y (the event's locationInWindow — gesture events report the
     * pointer location, not a midpoint between the fingers). */
    NATIVE_SDK_APPKIT_GPU_INPUT_PINCH_BEGIN = 12,
    NATIVE_SDK_APPKIT_GPU_INPUT_PINCH_CHANGE = 13,
    NATIVE_SDK_APPKIT_GPU_INPUT_PINCH_END = 14,
} native_sdk_appkit_gpu_input_kind_t;

typedef enum {
    NATIVE_SDK_APPKIT_CURSOR_ARROW = 0,
    NATIVE_SDK_APPKIT_CURSOR_POINTING_HAND = 1,
    NATIVE_SDK_APPKIT_CURSOR_TEXT = 2,
    NATIVE_SDK_APPKIT_CURSOR_RESIZE_HORIZONTAL = 3,
} native_sdk_appkit_cursor_t;

typedef enum {
    NATIVE_SDK_APPKIT_VIEW_WEBVIEW = 0,
    NATIVE_SDK_APPKIT_VIEW_TOOLBAR = 1,
    NATIVE_SDK_APPKIT_VIEW_TITLEBAR_ACCESSORY = 2,
    NATIVE_SDK_APPKIT_VIEW_SIDEBAR = 3,
    NATIVE_SDK_APPKIT_VIEW_STATUSBAR = 4,
    NATIVE_SDK_APPKIT_VIEW_SPLIT = 5,
    NATIVE_SDK_APPKIT_VIEW_STACK = 6,
    NATIVE_SDK_APPKIT_VIEW_BUTTON = 7,
    NATIVE_SDK_APPKIT_VIEW_TEXT_FIELD = 8,
    NATIVE_SDK_APPKIT_VIEW_SEARCH_FIELD = 9,
    NATIVE_SDK_APPKIT_VIEW_LABEL = 10,
    NATIVE_SDK_APPKIT_VIEW_SPACER = 11,
    NATIVE_SDK_APPKIT_VIEW_GPU_SURFACE = 12,
    NATIVE_SDK_APPKIT_VIEW_CHECKBOX = 13,
    NATIVE_SDK_APPKIT_VIEW_TOGGLE = 14,
    NATIVE_SDK_APPKIT_VIEW_PROGRESS_INDICATOR = 15,
    NATIVE_SDK_APPKIT_VIEW_SEGMENTED_CONTROL = 16,
    NATIVE_SDK_APPKIT_VIEW_ICON_BUTTON = 17,
    NATIVE_SDK_APPKIT_VIEW_LIST_ITEM = 18,
} native_sdk_appkit_view_kind_t;

typedef enum {
    NATIVE_SDK_APPKIT_WIDGET_ROLE_NONE = 0,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_GROUP = 1,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_TEXT = 2,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_IMAGE = 3,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_BUTTON = 4,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_TEXTBOX = 5,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_TOOLTIP = 6,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_DIALOG = 7,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_MENU = 8,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_MENUITEM = 9,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_LIST = 10,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_LISTITEM = 11,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_ROW = 12,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_GRID = 13,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_GRIDCELL = 14,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_TAB = 15,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_CHECKBOX = 16,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_SWITCH = 17,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_SLIDER = 18,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_PROGRESSBAR = 19,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_RADIO = 20,
    NATIVE_SDK_APPKIT_WIDGET_ROLE_RADIOGROUP = 21,
} native_sdk_appkit_widget_role_t;

enum {
    NATIVE_SDK_APPKIT_WIDGET_STATE_ENABLED = 1u << 0,
    NATIVE_SDK_APPKIT_WIDGET_STATE_FOCUSED = 1u << 1,
    NATIVE_SDK_APPKIT_WIDGET_STATE_SELECTED = 1u << 2,
    NATIVE_SDK_APPKIT_WIDGET_STATE_PRESSED = 1u << 3,
    NATIVE_SDK_APPKIT_WIDGET_STATE_EXPANDED = 1u << 4,
    NATIVE_SDK_APPKIT_WIDGET_STATE_COLLAPSED = 1u << 5,
    NATIVE_SDK_APPKIT_WIDGET_STATE_REQUIRED = 1u << 6,
    NATIVE_SDK_APPKIT_WIDGET_STATE_READ_ONLY = 1u << 7,
    NATIVE_SDK_APPKIT_WIDGET_STATE_INVALID = 1u << 8,
    NATIVE_SDK_APPKIT_WIDGET_STATE_CAN_UNDO = 1u << 9,
    NATIVE_SDK_APPKIT_WIDGET_STATE_CAN_REDO = 1u << 10,
};

enum {
    NATIVE_SDK_APPKIT_WIDGET_ACTION_FOCUS = 1u << 0,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_PRESS = 1u << 1,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_TOGGLE = 1u << 2,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_INCREMENT = 1u << 3,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_DECREMENT = 1u << 4,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_SET_TEXT = 1u << 5,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_SET_SELECTION = 1u << 6,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_SELECT = 1u << 7,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_DRAG = 1u << 8,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_DROP_FILES = 1u << 9,
    NATIVE_SDK_APPKIT_WIDGET_ACTION_DISMISS = 1u << 10,
};

typedef enum {
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_FOCUS = 0,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_PRESS = 1,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_TOGGLE = 2,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_INCREMENT = 3,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_DECREMENT = 4,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_SET_TEXT = 5,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_SET_SELECTION = 6,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_SELECT = 7,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_DRAG = 8,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_DROP_FILES = 9,
    NATIVE_SDK_APPKIT_WIDGET_ACCESSIBILITY_ACTION_DISMISS = 10,
} native_sdk_appkit_widget_accessibility_action_t;

typedef struct {
    uint64_t id;
    uint64_t parent_id;
    int role;
    const char *label;
    size_t label_len;
    const char *text_value;
    size_t text_value_len;
    const char *placeholder;
    size_t placeholder_len;
    int has_text_selection;
    size_t text_selection_start;
    size_t text_selection_end;
    int has_text_composition;
    size_t text_composition_start;
    size_t text_composition_end;
    int has_value;
    double value;
    int has_grid_row_index;
    size_t grid_row_index;
    int has_grid_column_index;
    size_t grid_column_index;
    int has_grid_row_count;
    size_t grid_row_count;
    int has_grid_column_count;
    size_t grid_column_count;
    int has_list_item_index;
    uint32_t list_item_index;
    int has_list_item_count;
    uint32_t list_item_count;
    int has_scroll_offset;
    double scroll_offset;
    int has_scroll_viewport_extent;
    double scroll_viewport_extent;
    int has_scroll_content_extent;
    double scroll_content_extent;
    double x;
    double y;
    double width;
    double height;
    uint32_t state_flags;
    uint32_t action_flags;
} native_sdk_appkit_widget_accessibility_node_t;

typedef struct {
    native_sdk_appkit_event_kind_t kind;
    uint64_t window_id;
    double width;
    double height;
    double scale;
    double x;
    double y;
    int open;
    int focused;
    /* WINDOW_FRAME: nonzero while the window is alive but hidden by
     * its close_policy (.hide intercepted a user close). open stays 1
     * for the window's whole hidden stretch. */
    int hidden;
    const char *label;
    size_t label_len;
    const char *shortcut_id;
    size_t shortcut_id_len;
    const char *shortcut_key;
    size_t shortcut_key_len;
    uint32_t shortcut_modifiers;
    const char *command_name;
    size_t command_name_len;
    /* TRAY_COMMAND: stable owner id for the status item that emitted it. */
    uint32_t status_item_id;
    const char *view_label;
    size_t view_label_len;
    const char *key_text;
    size_t key_text_len;
    const char *input_text;
    size_t input_text_len;
    const char *drop_paths;
    size_t drop_paths_len;
    uint64_t frame_index;
    uint64_t timestamp_ns;
    uint64_t frame_interval_ns;
    int nonblank;
    uint32_t sample_color;
    int input_kind;
    int button;
    double delta_x;
    double delta_y;
    uint64_t widget_id;
    int widget_action;
    const char *widget_text;
    size_t widget_text_len;
    int has_widget_text_selection;
    size_t widget_text_selection_start;
    size_t widget_text_selection_end;
    int has_composition_cursor;
    size_t composition_cursor;
    int color_scheme;
    int reduce_motion;
    int high_contrast;
    uint64_t timer_id;
    /* GPU_SURFACE_SCROLL_DRIVER / CONTEXT_MENU_ACTION payloads: widget_id
     * carries the driver id / menu token; scroll_driver_offset_x/_y the
     * new content offsets (canvas points, x-rightward, y-down,
     * overscroll passes through); menu_item_id the selected
     * context-menu item (0 = dismissed). */
    double scroll_driver_offset_x;
    double scroll_driver_offset_y;
    uint32_t menu_item_id;
    /* GPU_SURFACE_FRAME payloads: host-stamped durations of the most
     * recent packet present's decode and draw (0 when no packet present
     * happened since the last frame event), so the engine's frame
     * profile can attribute host time without a second channel. */
    uint64_t packet_decode_ns;
    uint64_t packet_draw_ns;
    /* Nonzero when this frame completed LOGICALLY while the window was
     * occluded (no glass flip; heartbeat pacing): the completion keeps
     * frame-channel consumers current, but its timestamp measures the
     * deliberate occluded cadence, not present latency — consumers must
     * not stamp latency measurements from it. */
    int occluded;
    /* EVENT_AUDIO payloads: the report kind
     * (native_sdk_appkit_audio_event_kind_t) plus the player's
     * position/duration readout in milliseconds at emit time. */
    int audio_kind;
    uint64_t audio_position_ms;
    uint64_t audio_duration_ms;
    int audio_playing;
    /* Nonzero while a streamed URL source is stalled waiting for
     * network bytes — distinct from audio_playing (transport intent):
     * a stream can be un-paused yet silent until bytes arrive. Local
     * files never buffer. */
    int audio_buffering;
    /* SPECTRUM payloads: the band magnitudes on the documented scale
     * (log-spaced 50 Hz..16 kHz buckets; each byte linear-in-dB from
     * the -60 dBFS analysis floor at 0 to full scale at 255). Zeros on
     * every other event kind. */
    uint8_t audio_bands[NATIVE_SDK_APPKIT_AUDIO_SPECTRUM_BANDS];
    /* EVENT_VIDEO payloads: the report kind
     * (native_sdk_appkit_video_event_kind_t) plus the player's
     * position/duration readout in milliseconds at emit time.
     * video_playing/video_buffering carry the audio event's exact
     * semantics (transport intent vs a stalled stream). */
    int video_kind;
    /* The engine-minted load token this playback echoes in every event
     * (see the Zig seam's VideoEvent.token): how a replaced playback's
     * queued straggler is told apart from the replacement's stream. */
    uint64_t video_token;
    uint64_t video_position_ms;
    uint64_t video_duration_ms;
    int video_playing;
    int video_buffering;
    /* LOADED payloads: the STREAM's decoded pixel dimensions — the
     * honest source geometry, even when the host downscales frames to
     * fit the sink's per-frame pixel budget. Zeros on every other
     * event kind. */
    uint64_t video_width;
    uint64_t video_height;
} native_sdk_appkit_event_t;

typedef void (*native_sdk_appkit_event_callback_t)(void *context, const native_sdk_appkit_event_t *event);
typedef void (*native_sdk_appkit_bridge_callback_t)(void *context, uint64_t window_id, const char *webview_label, size_t webview_label_len, const char *message, size_t message_len, const char *origin, size_t origin_len);

typedef struct native_sdk_update_verify_result {
    int ok;
    int error_code;
    size_t version_len;
    size_t archive_url_len;
    size_t release_notes_len;
    uint64_t archive_bytes;
    char sha256[64];
} native_sdk_update_verify_result_t;

native_sdk_update_verify_result_t native_sdk_update_verify_feed(
    const char *envelope, size_t envelope_len,
    const char *public_key, size_t public_key_len,
    const char *bundle_id, size_t bundle_id_len,
    const char *current_version, size_t current_version_len,
    const char *target, size_t target_len,
    char *version_out, size_t version_capacity,
    char *archive_url_out, size_t archive_url_capacity,
    char *release_notes_out, size_t release_notes_capacity);
int native_sdk_update_verify_archive(const char *path, size_t path_len, uint64_t expected_bytes, const char *sha256, size_t sha256_len);

// show_policy 0 = immediate (ordered front at create), 1 = deferred to
// the first canvas present (present-before-show: the window is created
// ordered-out and `makeKeyAndOrderFront` runs after the first
// gpu-surface present lands, with a short fallback deadline so a wedged
// first frame cannot leave the window invisible), 2 = explicitly hidden
// until a show/focus request.
//
// display_name is the human-facing app name (empty = fall back to
// app_name): it drives the application menu title and its About/Hide/
// Quit labels, the process name, the Dock/app-switcher entry, and the
// About panel, which also shows version and about_description when
// non-empty. has_web_content declares whether the app hosts a webview;
// web-only default menu items (Reload, Toggle Web Inspector, Undo/Redo)
// exist only when it is set. dock_visible selects Regular (nonzero) or
// Accessory (zero) before application configuration and window creation.
native_sdk_appkit_host_t *native_sdk_appkit_create(const char *app_name, size_t app_name_len, const char *display_name, size_t display_name_len, const char *version, size_t version_len, const char *about_description, size_t about_description_len, int has_web_content, int dock_visible, const char *window_title, size_t window_title_len, const char *bundle_id, size_t bundle_id_len, const char *icon_path, size_t icon_path_len, const char *window_label, size_t window_label_len, double x, double y, double width, double height, int restore_frame, int initial_placement, int restore_policy, int resizable, int titlebar_style, int show_policy, uint32_t window_flags);
void native_sdk_appkit_destroy(native_sdk_appkit_host_t *host);
// Adopt pre-rendered straight-alpha RGBA8 pixels as the Dock icon (and
// the About panel copy). The pixels are copied before return, so the
// caller may free its buffer immediately; adoption happens on the main
// queue. The Debug dev-run path renders the packaging pipeline's masked
// macOS canvas and delivers it here, so a raw square icon source shows
// the same rounded tile a packaged bundle would.
void native_sdk_appkit_set_dock_icon_rgba(native_sdk_appkit_host_t *host, const uint8_t *pixels, size_t width, size_t height);
// Load the Dock icon from an image file off the calling thread — the
// same decode configureApplication runs for the manifest icon. The
// Debug dev-run path falls back to this when its masked render fails,
// keeping the pre-masking behavior (icon shown unshaped) as the floor.
void native_sdk_appkit_set_dock_icon_file(native_sdk_appkit_host_t *host, const char *path, size_t path_len);
void native_sdk_appkit_configure_updates(native_sdk_appkit_host_t *host, const char *feed_url, size_t feed_url_len, const char *public_key, size_t public_key_len, int check_on_start, const char *target, size_t target_len);
int native_sdk_appkit_check_for_updates(native_sdk_appkit_host_t *host, int user_initiated);
void native_sdk_appkit_run(native_sdk_appkit_host_t *host, native_sdk_appkit_event_callback_t callback, void *context);
// The host-side shutdown request: a failed event emit asks the host to
// deliver SHUTDOWN and stop. While the run loop is live the delivery is
// queued to the next turn; before [NSApp run] it happens inline (the
// failed-START precedent — runWithCallback's didShutdown check honors
// it before the loop would start).
void native_sdk_appkit_stop(native_sdk_appkit_host_t *host);
// The quit VERB's landing point (fx.quitApp): always deferred, never
// inline — the verb arrives mid dispatch, and the shutdown must emit
// only after the requesting dispatch has committed to the session
// recorder. While the run loop is live the deferral is a main-queue
// hop; before [NSApp run] the request parks as a pending flag that
// runWithCallback drains at top level after the pre-run dispatch that
// carried it returns.
void native_sdk_appkit_request_stop(native_sdk_appkit_host_t *host);
void native_sdk_appkit_load_webview(native_sdk_appkit_host_t *host, const char *source, size_t source_len, int source_kind, const char *asset_root, size_t asset_root_len, const char *asset_entry, size_t asset_entry_len, const char *asset_origin, size_t asset_origin_len, int spa_fallback);
void native_sdk_appkit_load_window_webview(native_sdk_appkit_host_t *host, uint64_t window_id, const char *source, size_t source_len, int source_kind, const char *asset_root, size_t asset_root_len, const char *asset_entry, size_t asset_entry_len, const char *asset_origin, size_t asset_origin_len, int spa_fallback);
void native_sdk_appkit_set_bridge_callback(native_sdk_appkit_host_t *host, native_sdk_appkit_bridge_callback_t callback, void *context);
void native_sdk_appkit_bridge_respond(native_sdk_appkit_host_t *host, const char *response, size_t response_len);
void native_sdk_appkit_bridge_respond_window(native_sdk_appkit_host_t *host, uint64_t window_id, const char *response, size_t response_len);
void native_sdk_appkit_bridge_respond_webview(native_sdk_appkit_host_t *host, uint64_t window_id, const char *webview_label, size_t webview_label_len, const char *response, size_t response_len);
void native_sdk_appkit_emit_window_event(native_sdk_appkit_host_t *host, uint64_t window_id, const char *name, size_t name_len, const char *detail_json, size_t detail_json_len);
void native_sdk_appkit_set_security_policy(native_sdk_appkit_host_t *host, const char *allowed_origins, size_t allowed_origins_len, const char *external_urls, size_t external_urls_len, int external_action);
void native_sdk_appkit_set_menus(native_sdk_appkit_host_t *host, const char *const *menu_titles, const size_t *menu_title_lens, size_t menu_count, const uint32_t *item_menu_indices, const char *const *item_labels, const size_t *item_label_lens, const char *const *item_commands, const size_t *item_command_lens, const char *const *item_keys, const size_t *item_key_lens, const uint32_t *item_modifiers, const int *item_separators, const int *item_enabled, const int *item_checked, size_t item_count);
void native_sdk_appkit_set_shortcuts(native_sdk_appkit_host_t *host, const char *const *ids, const size_t *id_lens, const char *const *keys, const size_t *key_lens, const uint32_t *modifiers, size_t count);
int native_sdk_appkit_create_window(native_sdk_appkit_host_t *host, uint64_t window_id, const char *window_title, size_t window_title_len, const char *window_label, size_t window_label_len, double x, double y, double width, double height, int restore_frame, int initial_placement, int restore_policy, int resizable, int titlebar_style, int show_policy, uint32_t window_flags);
// Content min-size floor for a created window (NSWindow contentMinSize):
// the user's resize stops at the floor. Values <= 0 leave that axis at
// AppKit's default minimum. Returns 0 when the window id is unknown.
int native_sdk_appkit_set_window_content_min_size(native_sdk_appkit_host_t *host, uint64_t window_id, double min_width, double min_height);
int native_sdk_appkit_focus_window(native_sdk_appkit_host_t *host, uint64_t window_id);
int native_sdk_appkit_close_window(native_sdk_appkit_host_t *host, uint64_t window_id);
// The real OS minimize verb (NSWindow miniaturize:), for app-drawn
// window controls on chromeless windows. Returns 0 when the window id
// is unknown.
int native_sdk_appkit_minimize_window(native_sdk_appkit_host_t *host, uint64_t window_id);
// Order a live window out without closing it. `show_window` is the inverse.
int native_sdk_appkit_hide_window(native_sdk_appkit_host_t *host, uint64_t window_id);
// The show verb: bring the window back to the glass and activate the
// app (deminiaturize + makeKeyAndOrderFront) — the counterpart to a
// close_policy .hide hide, and the tray-menu "Open" consequence.
// Returns 0 when the window id is unknown.
int native_sdk_appkit_show_window(native_sdk_appkit_host_t *host, uint64_t window_id);
// Change the process activation policy: visible = regular (Dock/app
// switcher), hidden = accessory. Returns 1 when applied.
int native_sdk_appkit_set_dock_presence(native_sdk_appkit_host_t *host, int visible);
// SMAppService.mainApp status values: 0 not registered, 1 enabled,
// 2 requires approval, 3 not found; -1 when unavailable.
int native_sdk_appkit_launch_at_login_status(native_sdk_appkit_host_t *host);
int native_sdk_appkit_set_launch_at_login(native_sdk_appkit_host_t *host, int enabled);
// What the user's close affordance does to this window: 0 = quit (the
// default: really close; last close follows app exit semantics),
// 1 = hide (order out and keep running — the menu-bar-app shape).
// Applied right after create, like the content min-size floor.
// Returns 0 when the window id is unknown.
int native_sdk_appkit_set_window_close_policy(native_sdk_appkit_host_t *host, uint64_t window_id, int close_policy);
// Window-drag region channel: called during dispatch of the pointer-down
// that starts the gesture. Single click hands the event to
// -[NSWindow performWindowDragWithEvent:] (moves only on actual
// movement); a double-click applies the user's titlebar double-click
// action (zoom by default). Returns 0 when the window id is unknown.
int native_sdk_appkit_start_window_drag(native_sdk_appkit_host_t *host, uint64_t window_id);
// Chrome overlay geometry for hidden-titlebar windows: the bands where
// the transparent titlebar and traffic lights overlay the content view,
// plus the traffic-light cluster's bounding frame (content coordinates,
// top-left origin — so headers can vertically center against the lights
// in the tall unified band), in points. Standard-chrome windows and
// fullscreen report all-zero. Returns 0 when the window id is unknown
// (out-params untouched).
int native_sdk_appkit_window_chrome_insets(native_sdk_appkit_host_t *host, uint64_t window_id, double *top, double *left, double *bottom, double *right, double *buttons_x, double *buttons_y, double *buttons_width, double *buttons_height);
/* Per-window child WebViews. Both hosts implement these; declaring them
 * here keeps the definitions on C linkage (the Objective-C++ Chromium
 * host would otherwise mangle them and break the platform layer's extern
 * bindings). Each returns 1 on success, 0 when the window or webview is
 * unknown. */
int native_sdk_appkit_create_webview(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, const char *url, size_t url_len, double x, double y, double width, double height, int layer, int transparent, int bridge_enabled);
int native_sdk_appkit_set_webview_frame(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double x, double y, double width, double height);
int native_sdk_appkit_navigate_webview(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, const char *url, size_t url_len);
int native_sdk_appkit_set_webview_zoom(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double zoom);
int native_sdk_appkit_set_webview_layer(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, int layer);
int native_sdk_appkit_close_webview(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
int native_sdk_appkit_create_view(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, int kind, const char *parent, size_t parent_len, double x, double y, double width, double height, int layer, int visible, int enabled, const char *role, size_t role_len, const char *accessibility_label, size_t accessibility_label_len, const char *text, size_t text_len, const char *command, size_t command_len);
int native_sdk_appkit_update_view(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, int has_frame, double x, double y, double width, double height, int has_layer, int layer, int has_visible, int visible, int has_enabled, int enabled, int has_role, const char *role, size_t role_len, int has_accessibility_label, const char *accessibility_label, size_t accessibility_label_len, int has_text, const char *text, size_t text_len, int has_command, const char *command, size_t command_len);
int native_sdk_appkit_set_view_frame(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double x, double y, double width, double height);
int native_sdk_appkit_set_view_visible(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, int visible);
int native_sdk_appkit_set_view_cursor(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, int cursor);
int native_sdk_appkit_focus_view(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
int native_sdk_appkit_close_view(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
/* Native-surface adoption: install an app-owned NSView (`ns_view`, an
 * unretained NSView* the caller keeps alive elsewhere or transfers via the
 * superview retain) as the fill content of an existing native view created
 * through `native_sdk_appkit_create_view`. The adopted view is sized to the
 * container's bounds and autoresizes with it, so shell relayout keeps it
 * attached — the same containment shape webview-backed child views use,
 * generalized to views the framework did not construct (a
 * VZVirtualMachineView, an MKMapView, ...). Adopting over an existing
 * adoption replaces it. Main-thread only, like every other view call.
 * Returns 1 on success, 0 when the container is unknown or `ns_view` is not
 * an NSView. */
int native_sdk_appkit_adopt_view_surface(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, void *ns_view);
/* Remove the adopted surface from a container (the view itself stays
 * alive for the caller to reuse). Returns 1 on success, 0 when the
 * container has no adopted surface. */
int native_sdk_appkit_release_view_surface(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
int native_sdk_appkit_present_gpu_surface_pixels(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, size_t width, size_t height, double scale, int has_dirty_rect, double dirty_x, double dirty_y, double dirty_width, double dirty_height, const uint8_t *rgba8, size_t rgba8_len);
int native_sdk_appkit_present_gpu_surface_packet(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double surface_width, double surface_height, double scale, uint8_t clear_r, uint8_t clear_g, uint8_t clear_b, uint8_t clear_a, int requires_render, size_t command_count, size_t unsupported_command_count, int representable, const uint8_t *json, size_t json_len);
int native_sdk_appkit_present_gpu_surface_packet_binary(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double surface_width, double surface_height, double scale, uint8_t clear_r, uint8_t clear_g, uint8_t clear_b, uint8_t clear_a, int requires_render, size_t command_count, size_t unsupported_command_count, int representable, const uint8_t *packet, size_t packet_len);
int native_sdk_appkit_request_gpu_surface_frame(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
/* Input was dispatched to the surface (real or automation-synthesized):
 * the responding frame emission must not wait out the occluded
 * heartbeat. One-shot; a no-op for hosts/views without occluded pacing. */
int native_sdk_appkit_note_gpu_surface_input(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len);
/* Binary image-upload side-channel: create or replace the host-wide image
 * for `image_id` from tightly packed, row-major, straight-alpha RGBA8
 * bytes (`rgba8_len` must equal width * height * 4). Packet upload cache
 * actions resolve pixels from this store — packet JSON never carries pixel
 * payloads. Returns 1 on success, 0 on invalid arguments. */
int native_sdk_appkit_upload_gpu_surface_image(native_sdk_appkit_host_t *host, uint64_t image_id, size_t width, size_t height, const uint8_t *rgba8, size_t rgba8_len);
/* Drop the host-wide image for `image_id` (the unregister path). Removing
 * an unknown id is a no-op. Returns 1 on success, 0 on invalid arguments. */
int native_sdk_appkit_remove_gpu_surface_image(native_sdk_appkit_host_t *host, uint64_t image_id);
void native_sdk_appkit_start_timer(native_sdk_appkit_host_t *host, uint64_t timer_id, uint64_t interval_ns, int repeats);
void native_sdk_appkit_cancel_timer(native_sdk_appkit_host_t *host, uint64_t timer_id);

/* The app's single audio player (AVAudioPlayer). Load replaces whatever
 * was loaded before, paused at position zero; returns 0 on success, 1
 * when the file is missing/unreadable, 2 when it cannot be decoded. A
 * successful load is followed by one EVENT_AUDIO/LOADED on the run loop
 * carrying the decoded duration. Play/pause/stop/seek/set_volume return
 * 1 when applied, 0 when there is no loaded player to apply to (stop,
 * pause, and set_volume treat that as a harmless no-op on the Zig side).
 * All entries are loop-thread only. */
int native_sdk_appkit_audio_load(native_sdk_appkit_host_t *host, const char *path, size_t path_len);
/* URL sources on the same single player. Resolution is honest and
 * two-step: a verified cache entry at cache_path (present, and
 * expected_bytes matches when nonzero — a partial or stale entry never
 * plays; it is deleted and re-streamed) plays as a plain local file and
 * returns 1; otherwise playback STREAMS progressively via AVPlayer —
 * audible as soon as enough bytes arrive, never download-then-play —
 * while a parallel download fills cache_path for next time (written to
 * a .part sibling, size-verified, then atomically renamed into place)
 * and the call returns 0. An empty cache_path disables caching. Returns
 * 2 when the URL cannot even be parsed. Async failures (unreachable
 * host, mid-stream network loss, undecodable payload) arrive as one
 * EVENT_AUDIO/FAILED on the run loop. Loop-thread only. */
int native_sdk_appkit_audio_load_url(native_sdk_appkit_host_t *host, const char *url, size_t url_len, const char *cache_path, size_t cache_path_len, uint64_t expected_bytes);
int native_sdk_appkit_audio_play(native_sdk_appkit_host_t *host);
int native_sdk_appkit_audio_pause(native_sdk_appkit_host_t *host);
int native_sdk_appkit_audio_stop(native_sdk_appkit_host_t *host);
int native_sdk_appkit_audio_seek(native_sdk_appkit_host_t *host, uint64_t position_ms);
int native_sdk_appkit_audio_set_volume(native_sdk_appkit_host_t *host, double volume);

/* Microphone/system-output capture. Source: 0 microphone, 1 system;
 * event kind: 0 started, 1 PCM data, 2 failed. PCM is interleaved signed
 * 16-bit little-endian in the exact requested format. The callback returns
 * 0 accepted, 1 closed (the producer must exit), or a drop code. Stop is a
 * synchronous quiescence fence: the callback is never entered afterward. */
typedef int (*native_sdk_appkit_audio_capture_push_t)(void *context, int kind, int source, uint32_t sample_rate, uint8_t channels, uint64_t timestamp_ns, uint32_t frames, const uint8_t *pcm, size_t pcm_len);
int native_sdk_appkit_audio_capture_start(native_sdk_appkit_host_t *host, int source, uint32_t sample_rate, uint8_t channels, native_sdk_appkit_audio_capture_push_t push_fn, void *push_context);
int native_sdk_appkit_audio_capture_stop(native_sdk_appkit_host_t *host, int source);
int native_sdk_appkit_audio_capture_supported(native_sdk_appkit_host_t *host, int source);

/* Where the video player delivers decoded frames: one tightly packed,
 * row-major, straight-alpha RGBA8 frame per call (len = width * height
 * * 4), copied before return. Returns 0 when the frame was accepted, 1
 * when the receiving claim has been released (the host must stop
 * pushing — its frame timer has nothing left to feed), anything else a
 * dropped frame (latest-wins; the host keeps decoding). Always invoked
 * on the main run loop. */
typedef int (*native_sdk_appkit_video_sink_push_t)(void *context, size_t width, size_t height, const uint8_t *pixels, size_t len);

/* The app's single video player (AVPlayer + AVPlayerItemVideoOutput).
 * Load replaces whatever was loaded before, paused at position zero;
 * returns 0 on success, 1 when the file is missing/unreadable, 2 when
 * it cannot be decoded. A successful load is followed by one
 * EVENT_VIDEO/LOADED on the run loop carrying the stream's dimensions
 * and the decoded duration; decoded frames flow through push_fn.
 * Play/pause/stop/seek/set_volume/set_muted/set_loop return 1 when
 * applied, 0 when there is no loaded player to apply to (stop, pause,
 * and the setters treat that as a harmless no-op on the Zig side).
 * All entries are loop-thread only. */
int native_sdk_appkit_video_load(native_sdk_appkit_host_t *host, const char *path, size_t path_len, uint64_t token, native_sdk_appkit_video_sink_push_t push_fn, void *push_context);
/* URL sources on the same single player: progressive AVPlayer streaming
 * (playable as soon as enough bytes arrive, never download-then-play;
 * no cache layer). Returns 2 when the URL cannot even be parsed, 0 for
 * a started stream. Async failures (unreachable host, mid-stream
 * network loss, undecodable payload) arrive as one EVENT_VIDEO/FAILED
 * on the run loop. Loop-thread only. */
int native_sdk_appkit_video_load_url(native_sdk_appkit_host_t *host, const char *url, size_t url_len, uint64_t token, native_sdk_appkit_video_sink_push_t push_fn, void *push_context);
int native_sdk_appkit_video_play(native_sdk_appkit_host_t *host);
int native_sdk_appkit_video_pause(native_sdk_appkit_host_t *host);
int native_sdk_appkit_video_stop(native_sdk_appkit_host_t *host);
int native_sdk_appkit_video_seek(native_sdk_appkit_host_t *host, uint64_t position_ms);
int native_sdk_appkit_video_set_volume(native_sdk_appkit_host_t *host, double volume);
int native_sdk_appkit_video_set_muted(native_sdk_appkit_host_t *host, int muted);
int native_sdk_appkit_video_set_loop(native_sdk_appkit_host_t *host, int loop);
/* Thread-safe: nudges the main run loop to emit a WAKE event. May be
 * called from any thread (worker threads streaming effect results). */
void native_sdk_appkit_wake(native_sdk_appkit_host_t *host);
/* Thread-safe: asks the main run loop to emit ONE coalesced FRAME event.
 * May be called from any thread; the automation arrival watcher uses it
 * so a command landing in the dropbox wakes an idle app's frame loop the
 * way user input does. Timer-free by design: the event is posted through
 * the main queue, so it is delivered promptly even when the app is
 * backgrounded and its NSTimers are being coalesced. */
void native_sdk_appkit_request_frame(native_sdk_appkit_host_t *host);
int native_sdk_appkit_update_widget_accessibility(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, const native_sdk_appkit_widget_accessibility_node_t *nodes, size_t node_count);
size_t native_sdk_appkit_clipboard_read(native_sdk_appkit_host_t *host, char *buffer, size_t buffer_len);
double native_sdk_appkit_measure_text(uint64_t font_id, double size, const char *text, size_t text_len);

/* Batched measurement: fill advances[text_len] with per-cluster
 * typographic advances for the whole single-line run, shaped with the
 * same font resolution native_sdk_appkit_measure_text measures with.
 * Layout contract: the advance of the UTF-8 cluster starting at byte i
 * lands at advances[i]; the cluster's continuation bytes hold exactly 0.
 * One call per run replaces one measure_text round-trip per cluster of
 * every growing line prefix. Returns 1 on success, 0 when the bytes are
 * not valid UTF-8 or the font id cannot resolve (the engine then keeps
 * its per-prefix path for that run). */
int native_sdk_appkit_measure_text_advances(uint64_t font_id, double size, const char *text, size_t text_len, float *advances);
/* Shaped glyph-path bounds for one line, relative to its baseline. */
int native_sdk_appkit_measure_text_ink(uint64_t font_id, double size, const char *text, size_t text_len, double *min_x, double *max_x, double *min_y, double *max_y);

// Register engine-validated TrueType bytes under a canvas font id so
// measurement and packet text drawing resolve the id to this exact face.
// Returns 1 on success, 0 when CoreText rejects the data. On success
// `*out_token` is the registration's ownership token — the handle the
// caller must present to native_sdk_appkit_unregister_font, so teardown
// removes exactly this registration (font ids are per-runtime while
// host font state is per-process: a later runtime may re-register the
// id, and its live face must survive the older owner's teardown). Hosts
// that retain no font state (the Chromium engine's stateless accept)
// write 0: nothing installed, nothing a token could own.
int native_sdk_appkit_register_font(uint64_t font_id, const uint8_t *bytes, size_t bytes_len, uint64_t *out_token);
// Drop the per-id state a registration installed (the descriptor and its
// caches) — the teardown twin Runtime.deinit calls, because font ids are
// per-runtime while this host's font state is per-process. `token` must
// be the value the matching register call reported: state is removed
// only while the id's current registration still carries it, so an
// older runtime's deinit never tears down a newer runtime's live face
// under a shared id. A stale token — like an id with no installed
// descriptor — is a no-op accept: the registration the token owned is
// already gone, which is the state the caller asked for. Returns 1 on
// accept, 0 only for the invalid id 0.
int native_sdk_appkit_unregister_font(uint64_t font_id, uint64_t token);
/* Decode encoded image bytes (PNG, JPEG, ... through ImageIO; SVG through
 * NSImage's system rasterizer) into tightly packed, row-major, straight-alpha
 * (non-premultiplied) RGBA8 written into `pixels`. Returns 1 on success
 * (with `out_width`/`out_height` set), 0 when the bytes cannot be decoded,
 * and -1 when the decoded pixels do not fit `pixels_len` (`out_width`/
 * `out_height` still report the decoded dimensions). It retains no AppKit
 * state, needs no host, and is main-thread independent. */
int native_sdk_appkit_decode_image(const uint8_t *bytes, size_t bytes_len, uint8_t *pixels, size_t pixels_len, size_t max_pixels, size_t *out_width, size_t *out_height);
void native_sdk_appkit_clipboard_write(native_sdk_appkit_host_t *host, const char *text, size_t text_len);
size_t native_sdk_appkit_clipboard_read_data(native_sdk_appkit_host_t *host, const char *mime_type, size_t mime_type_len, char *buffer, size_t buffer_len);
int native_sdk_appkit_clipboard_write_data(native_sdk_appkit_host_t *host, const char *mime_type, size_t mime_type_len, const char *bytes, size_t bytes_len);
int native_sdk_appkit_show_notification(native_sdk_appkit_host_t *host, const char *title, size_t title_len, const char *subtitle, size_t subtitle_len, const char *body, size_t body_len, const char *notification_id, size_t notification_id_len, const char *action_label, size_t action_label_len, const char *action_command, size_t action_command_len);
int native_sdk_appkit_open_external_url(native_sdk_appkit_host_t *host, const char *url, size_t url_len);
int native_sdk_appkit_reveal_path(native_sdk_appkit_host_t *host, const char *path, size_t path_len);
int native_sdk_appkit_add_recent_document(native_sdk_appkit_host_t *host, const char *path, size_t path_len);
int native_sdk_appkit_clear_recent_documents(native_sdk_appkit_host_t *host);
int native_sdk_appkit_set_credential(native_sdk_appkit_host_t *host, const char *service, size_t service_len, const char *account, size_t account_len, const char *secret, size_t secret_len);
size_t native_sdk_appkit_get_credential(native_sdk_appkit_host_t *host, const char *service, size_t service_len, const char *account, size_t account_len, char *buffer, size_t buffer_len);
int native_sdk_appkit_delete_credential(native_sdk_appkit_host_t *host, const char *service, size_t service_len, const char *account, size_t account_len);
size_t native_sdk_appkit_format_local_time(native_sdk_appkit_host_t *host, int64_t timestamp_ms, int style, char *buffer, size_t buffer_len);

typedef struct {
    const char *title;
    size_t title_len;
    const char *default_path;
    size_t default_path_len;
    const char *extensions;
    size_t extensions_len;
    int allow_directories;
    int allow_multiple;
} native_sdk_appkit_open_dialog_opts_t;

typedef struct {
    size_t count;
    size_t bytes_written;
} native_sdk_appkit_open_dialog_result_t;

typedef struct {
    const char *title;
    size_t title_len;
    const char *default_path;
    size_t default_path_len;
    const char *default_name;
    size_t default_name_len;
    const char *extensions;
    size_t extensions_len;
} native_sdk_appkit_save_dialog_opts_t;

typedef struct {
    int style;
    const char *title;
    size_t title_len;
    const char *message;
    size_t message_len;
    const char *informative_text;
    size_t informative_text_len;
    const char *primary_button;
    size_t primary_button_len;
    const char *secondary_button;
    size_t secondary_button_len;
    const char *tertiary_button;
    size_t tertiary_button_len;
} native_sdk_appkit_message_dialog_opts_t;

typedef void (*native_sdk_appkit_tray_callback_t)(void *context, uint32_t status_item_id, uint32_t item_id);

typedef struct {
    uint32_t item_id;
    const char *label;
    size_t label_len;
    int selected;
    int enabled;
} native_sdk_appkit_tray_segment_option_t;

typedef struct {
    size_t row_index;
    const native_sdk_appkit_tray_segment_option_t *options;
    size_t option_count;
} native_sdk_appkit_tray_segmented_row_t;

typedef struct {
    size_t row_index;
    const char *primary_text;
    size_t primary_text_len;
    const char *secondary_text;
    size_t secondary_text_len;
    const char *accessibility_label;
    size_t accessibility_label_len;
} native_sdk_appkit_tray_metric_row_t;

typedef struct {
    size_t row_index;
    const float *values;
    size_t value_count;
    double min_value;
    double max_value;
    const char *leading_caption;
    size_t leading_caption_len;
    const char *trailing_summary;
    size_t trailing_summary_len;
    const char *accessibility_label;
    size_t accessibility_label_len;
} native_sdk_appkit_tray_chart_row_t;

/* One native scroll driver's desired state (see PlatformServices
 * set_gpu_surface_scroll_drivers_fn). Frame coordinates are view-local
 * canvas points (top-left origin, y-down); the host flips to AppKit
 * coordinates itself. */
/* A surface that hit-blocks scroll regions beneath it (view-local
 * canvas points, top-left origin): wheel routing declines a driver
 * whose occluder mask includes an occluder containing the point. */
typedef struct {
    double x;
    double y;
    double width;
    double height;
} native_sdk_appkit_scroll_occluder_t;

typedef struct {
    uint64_t driver_id;
    /* The nearest ancestor driver's id (0 = none): wheel-owner
     * resolution is restricted to the hit region and its ancestors. */
    uint64_t parent_driver_id;
    /* Bit i set = occluder i (of the sync call's occluder array) blocks
     * this region at points it contains. */
    uint32_t occluder_mask;
    double x;
    double y;
    double width;
    double height;
    double content_width;
    double content_height;
    double offset_x;
    double offset_y;
    int set_offset_x;
    int set_offset_y;
    /* Edge behavior: 0 pins scrolling at the content edges, nonzero lets
     * the scroller bounce past them (armed per axis via the grants). */
    int rubber_band;
    /* Which axes the region grants: elasticity and scroller chrome arm
     * only on granted axes; an ungranted axis never moves or bounces. */
    int scrolls_x;
    int scrolls_y;
} native_sdk_appkit_scroll_driver_t;

/* One native context-menu entry. */
typedef struct {
    uint32_t item_id;
    const char *label;
    size_t label_len;
    int enabled;
    int separator;
} native_sdk_appkit_context_menu_item_t;

/* Reconcile the gpu-surface view's native scroll drivers against the full
 * desired set: create missing NSScrollViews, update frames / content
 * extents / (when set_offset) offsets, remove drivers absent from the
 * list. Idempotent; called every layout install and every presented
 * frame. Returns 1 on success, 0 when the view does not exist. */
int native_sdk_appkit_set_gpu_surface_scroll_drivers(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, const native_sdk_appkit_scroll_driver_t *drivers, size_t count, const native_sdk_appkit_scroll_occluder_t *occluders, size_t occluder_count);

/* Present a native context menu (NSMenu popUpMenuPositioningItem) at the
 * view-local point on the next main-loop turn. The selection (or
 * dismissal: menu_item_id 0) is emitted asynchronously as a
 * CONTEXT_MENU_ACTION event echoing `token` in widget_id. Returns 1 when
 * the request was queued, 0 when the window does not exist. */
int native_sdk_appkit_show_context_menu(native_sdk_appkit_host_t *host, uint64_t window_id, const char *label, size_t label_len, double x, double y, uint64_t token, const native_sdk_appkit_context_menu_item_t *items, size_t count);

native_sdk_appkit_open_dialog_result_t native_sdk_appkit_show_open_dialog(native_sdk_appkit_host_t *host, const native_sdk_appkit_open_dialog_opts_t *opts, char *buffer, size_t buffer_len);
size_t native_sdk_appkit_show_save_dialog(native_sdk_appkit_host_t *host, const native_sdk_appkit_save_dialog_opts_t *opts, char *buffer, size_t buffer_len);
int native_sdk_appkit_show_message_dialog(native_sdk_appkit_host_t *host, const native_sdk_appkit_message_dialog_opts_t *opts);
void native_sdk_appkit_create_tray(native_sdk_appkit_host_t *host, uint32_t status_item_id, const char *icon_path, size_t icon_path_len, const char *title, size_t title_len, const char *tooltip, size_t tooltip_len, int visible, double width, int tone, double icon_opacity, int monospaced, double font_size, int font_weight, const char *activation_command, size_t activation_command_len, const char *alternate_activation_command, size_t alternate_activation_command_len, const char *open_command, size_t open_command_len);
void native_sdk_appkit_update_tray_shell(native_sdk_appkit_host_t *host, uint32_t status_item_id, const char *icon_path, size_t icon_path_len, const char *tooltip, size_t tooltip_len, int visible, const char *activation_command, size_t activation_command_len, const char *alternate_activation_command, size_t alternate_activation_command_len, const char *open_command, size_t open_command_len);
void native_sdk_appkit_update_tray_menu(native_sdk_appkit_host_t *host, uint32_t status_item_id, const uint32_t *item_ids, const char *const *labels, const size_t *label_lens, const int *separators, const int *enabled_flags, const char *const *details, const size_t *detail_lens, const int *roles, const char *const *keys, const size_t *key_lens, const uint32_t *modifiers, size_t count);
void native_sdk_appkit_update_tray_rich_rows(native_sdk_appkit_host_t *host, uint32_t status_item_id, const native_sdk_appkit_tray_segmented_row_t *segmented_rows, size_t segmented_count, const native_sdk_appkit_tray_metric_row_t *metric_rows, size_t metric_count, const native_sdk_appkit_tray_chart_row_t *chart_rows, size_t chart_count);
/* Retitle the live status item's button without re-creating it (create
 * would flicker and reshuffle the menu bar). Empty title falls back to
 * the icon-only square well, or the app-name initial when there is no
 * icon either — the same fallbacks as create. */
void native_sdk_appkit_update_tray_title(native_sdk_appkit_host_t *host, uint32_t status_item_id, const char *title, size_t title_len);
void native_sdk_appkit_update_tray_presentation(native_sdk_appkit_host_t *host, uint32_t status_item_id, const char *title, size_t title_len, double width, int tone, double icon_opacity, int monospaced, double font_size, int font_weight);
void native_sdk_appkit_remove_tray(native_sdk_appkit_host_t *host, uint32_t status_item_id);
void native_sdk_appkit_set_tray_callback(native_sdk_appkit_host_t *host, native_sdk_appkit_tray_callback_t callback, void *context);

#ifdef __cplusplus
}
#endif

#endif
