// el-native — El native widget system, macOS AppKit target.
//
// This vessel wraps the __widget_* C builtins (added to el_seed.c under
// EL_TARGET_MACOS) in clean El-level functions. Applications import this
// vessel and use these functions directly.
//
// The el-ui-compiler's native codegen target emits calls to these functions
// when it processes component templates.
//
// Layer hierarchy:
//   Application .el
//       → el-native functions (this file)
//           → __widget_* / __window_* C builtins
//               → el_appkit.m ObjC bridge
//                   → AppKit NSWindow / NSView / NSButton / etc.
//
// Widget handles are opaque Int values. -1 means invalid/null.
// Pass handles between functions freely — they are small integers.
//
// Color convention: r/g/b/a are Float values 0.0–1.0.
// Use color_from_hex() or color_from_rgba() to build color arguments.

// ── Bootstrap ────────────────────────────────────────────────────────────────

// init — initialize the native widget system. Call once before creating widgets.
fn native_init() -> Void {
    __native_init()
}

// run_loop — start the platform run loop. Never returns.
// Call this as the final step of your application entry point.
fn native_run_loop() -> Void {
    __native_run_loop()
}

// ── Manifest ─────────────────────────────────────────────────────────────────

// manifest_read — parse the app{} block from a manifest.el file.
// Returns a JSON string: {"title":"...","width":N,"height":N,"min_width":N,"min_height":N}
fn manifest_read(path: String) -> String {
    __manifest_read(path)
}

fn manifest_title(m: String) -> String {
    json_get_string(m, "title")
}

fn manifest_width(m: String) -> Int {
    json_get_int(m, "width")
}

fn manifest_height(m: String) -> Int {
    json_get_int(m, "height")
}

fn manifest_min_width(m: String) -> Int {
    json_get_int(m, "min_width")
}

fn manifest_min_height(m: String) -> Int {
    json_get_int(m, "min_height")
}

// ── Window ───────────────────────────────────────────────────────────────────

// window_create — create a native window. Returns handle (Int).
// Reads sizing from manifest. Most apps should call window_from_manifest().
fn window_create(title: String, width: Int, height: Int,
                 min_width: Int, min_height: Int) -> Int {
    __window_create(title, width, height, min_width, min_height)
}

// window_from_manifest — create a window using settings from manifest.el.
fn window_from_manifest(manifest_path: String) -> Int {
    let m: String = manifest_read(manifest_path)
    let title: String = manifest_title(m)
    let w: Int = manifest_width(m)
    let h: Int = manifest_height(m)
    let mw: Int = manifest_min_width(m)
    let mh: Int = manifest_min_height(m)
    let safe_w: Int  = if w > 0  { w }  else { 1200 }
    let safe_h: Int  = if h > 0  { h }  else { 800 }
    let safe_mw: Int = if mw > 0 { mw } else { 600 }
    let safe_mh: Int = if mh > 0 { mh } else { 400 }
    let safe_t: String = if str_len(title) > 0 { title } else { "App" }
    window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh)
}

fn window_show(handle: Int) -> Void {
    __window_show(handle)
}

fn window_set_title(handle: Int, title: String) -> Void {
    __window_set_title(handle, title)
}

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

// vstack — vertical stack. Children are laid out top-to-bottom.
fn vstack(spacing: Int) -> Int {
    __vstack_create(spacing)
}

// vstack_tight — 0 spacing vertical stack.
fn vstack_tight() -> Int {
    __vstack_create(0)
}

// hstack — horizontal stack. Children are laid out left-to-right.
fn hstack(spacing: Int) -> Int {
    __hstack_create(spacing)
}

// zstack — children are layered on top of each other (Z axis).
fn zstack() -> Int {
    __zstack_create()
}

// scroll — scrollable container. Add a single child (usually a vstack).
fn scroll() -> Int {
    __scroll_create()
}

// ── Widgets ──────────────────────────────────────────────────────────────────

// label — static text display.
fn label(text: String) -> Int {
    __label_create(text)
}

// button — tappable button. Register handler with widget_on_click().
fn button(label: String) -> Int {
    __button_create(label)
}

// text_field — single-line text input.
fn text_field(placeholder: String) -> Int {
    __text_field_create(placeholder)
}

// text_area — multi-line text input.
fn text_area(placeholder: String) -> Int {
    __text_area_create(placeholder)
}

// image — display an image by filesystem path or system image name.
fn image(path_or_name: String) -> Int {
    __image_create(path_or_name)
}

// ── Widget properties ─────────────────────────────────────────────────────────

fn widget_set_text(handle: Int, text: String) -> Void {
    __widget_set_text(handle, text)
}

fn widget_get_text(handle: Int) -> String {
    __widget_get_text(handle)
}

// Color setters. r/g/b/a are Float 0.0–1.0.
fn widget_set_color(handle: Int, r: Float, g: Float, b: Float, a: Float) -> Void {
    __widget_set_color(handle, r, g, b, a)
}

fn widget_set_bg_color(handle: Int, r: Float, g: Float, b: Float, a: Float) -> Void {
    __widget_set_bg_color(handle, r, g, b, a)
}

// widget_set_font — set font family, size (pt), and bold flag.
// Use "system" or "" for the platform default font.
fn widget_set_font(handle: Int, family: String, size: Int, bold: Bool) -> Void {
    let bold_int: Int = if bold { 1 } else { 0 }
    __widget_set_font(handle, family, size, bold_int)
}

// widget_set_padding — set padding on all four sides (pixels).
fn widget_set_padding(handle: Int, top: Int, right: Int, bottom: Int, left: Int) -> Void {
    __widget_set_padding(handle, top, right, bottom, left)
}

// widget_set_padding_all — uniform padding on all sides.
fn widget_set_padding_all(handle: Int, p: Int) -> Void {
    __widget_set_padding(handle, p, p, p, p)
}

// widget_set_padding_xy — horizontal and vertical padding.
fn widget_set_padding_xy(handle: Int, px: Int, py: Int) -> Void {
    __widget_set_padding(handle, py, px, py, px)
}

fn widget_set_width(handle: Int, width: Int) -> Void {
    __widget_set_width(handle, width)
}

fn widget_set_height(handle: Int, height: Int) -> Void {
    __widget_set_height(handle, height)
}

// widget_set_flex — flex > 0 means expand to fill available space.
fn widget_set_flex(handle: Int, flex: Int) -> Void {
    __widget_set_flex(handle, flex)
}

fn widget_set_corner_radius(handle: Int, radius: Int) -> Void {
    __widget_set_corner_radius(handle, radius)
}

fn widget_set_disabled(handle: Int, disabled: Bool) -> Void {
    let d: Int = if disabled { 1 } else { 0 }
    __widget_set_disabled(handle, d)
}

fn widget_set_hidden(handle: Int, hidden: Bool) -> Void {
    let h: Int = if hidden { 1 } else { 0 }
    __widget_set_hidden(handle, h)
}

// ── Layout ───────────────────────────────────────────────────────────────────

fn widget_add_child(parent: Int, child: Int) -> Void {
    __widget_add_child(parent, child)
}

fn widget_remove_child(parent: Int, child: Int) -> Void {
    __widget_remove_child(parent, child)
}

fn widget_destroy(handle: Int) -> Void {
    __widget_destroy(handle)
}

// ── Events ───────────────────────────────────────────────────────────────────

// widget_on_click — register an El function to call when widget is clicked.
// fn_name: the compiled El symbol name of the handler function.
// Handler signature: fn my_handler(widget: Int, data: String) -> Void
fn widget_on_click(handle: Int, fn_name: String) -> Void {
    __widget_on_click(handle, fn_name)
}

// widget_on_change — called when text field value changes.
fn widget_on_change(handle: Int, fn_name: String) -> Void {
    __widget_on_change(handle, fn_name)
}

// widget_on_submit — called when text field receives Enter (submit).
fn widget_on_submit(handle: Int, fn_name: String) -> Void {
    __widget_on_submit(handle, fn_name)
}

// widget_set_data — attach an arbitrary data string to a widget.
// The data string is passed as the `data` argument when the widget's click
// callback fires. Use this to associate a session ID (or any identifier)
// with a clickable row so the callback knows which item was selected.
fn widget_set_data(handle: Int, data: String) -> Void {
    __widget_set_data(handle, data)
}

// ── Color helpers ─────────────────────────────────────────────────────────────
//
// Colors are passed as Float components (0.0–1.0). These helpers convert from
// common formats.

// hex_channel — parse two hex digits as a byte 0..255.
fn hex_channel(s: String, offset: Int) -> Int {
    let hi: String = str_slice(s, offset, offset + 1)
    let lo: String = str_slice(s, offset + 1, offset + 2)
    let h: Int = hex_nibble(hi)
    let l: Int = hex_nibble(lo)
    h * 16 + l
}

fn hex_nibble(c: String) -> Int {
    if str_eq(c, "0") { return 0 }
    if str_eq(c, "1") { return 1 }
    if str_eq(c, "2") { return 2 }
    if str_eq(c, "3") { return 3 }
    if str_eq(c, "4") { return 4 }
    if str_eq(c, "5") { return 5 }
    if str_eq(c, "6") { return 6 }
    if str_eq(c, "7") { return 7 }
    if str_eq(c, "8") { return 8 }
    if str_eq(c, "9") { return 9 }
    if str_eq(c, "a") { return 10 }
    if str_eq(c, "b") { return 11 }
    if str_eq(c, "c") { return 12 }
    if str_eq(c, "d") { return 13 }
    if str_eq(c, "e") { return 14 }
    if str_eq(c, "f") { return 15 }
    if str_eq(c, "A") { return 10 }
    if str_eq(c, "B") { return 11 }
    if str_eq(c, "C") { return 12 }
    if str_eq(c, "D") { return 13 }
    if str_eq(c, "E") { return 14 }
    if str_eq(c, "F") { return 15 }
    0
}

// color_hex_r/g/b/a — extract RGBA Float components from a hex color string.
// Accepts "#RRGGBB" or "#RRGGBBAA".
fn color_hex_r(hex: String) -> Float {
    let s: String = if str_starts_with(hex, "#") { str_slice(hex, 1, str_len(hex)) } else { hex }
    let v: Int = hex_channel(s, 0)
    float_div(int_to_float(v), 255.0)
}

fn color_hex_g(hex: String) -> Float {
    let s: String = if str_starts_with(hex, "#") { str_slice(hex, 1, str_len(hex)) } else { hex }
    let v: Int = hex_channel(s, 2)
    float_div(int_to_float(v), 255.0)
}

fn color_hex_b(hex: String) -> Float {
    let s: String = if str_starts_with(hex, "#") { str_slice(hex, 1, str_len(hex)) } else { hex }
    let v: Int = hex_channel(s, 4)
    float_div(int_to_float(v), 255.0)
}

fn color_hex_a(hex: String) -> Float {
    let s: String = if str_starts_with(hex, "#") { str_slice(hex, 1, str_len(hex)) } else { hex }
    if str_len(s) < 8 { return 1.0 }
    let v: Int = hex_channel(s, 6)
    float_div(int_to_float(v), 255.0)
}

// widget_set_color_hex — convenience: set foreground color from a hex string.
fn widget_set_color_hex(handle: Int, hex: String) -> Void {
    widget_set_color(handle,
        color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex))
}

// widget_set_bg_color_hex — convenience: set background color from a hex string.
fn widget_set_bg_color_hex(handle: Int, hex: String) -> Void {
    widget_set_bg_color(handle,
        color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex))
}

// ── Style tokens → native ─────────────────────────────────────────────────────
//
// Map el-style semantic tokens (from el-style vessel) to native widget properties.
// This is the bridge between the design system and platform rendering.
//
// Token colors match el-style's color_scheme_dark() by default.
// Applications can override by calling the individual setters directly.

let TOKEN_PRIMARY:     String = "#60a5fa"
let TOKEN_ON_PRIMARY:  String = "#0f172a"
let TOKEN_BACKGROUND:  String = "#0f172a"
let TOKEN_ON_BG:       String = "#f8fafc"
let TOKEN_SURFACE:     String = "#1e293b"
let TOKEN_ON_SURFACE:  String = "#f8fafc"
let TOKEN_OUTLINE:     String = "#475569"
let TOKEN_ERROR:       String = "#f87171"

// Apply standard surface styling to a container.
fn style_surface(handle: Int) -> Void {
    widget_set_bg_color_hex(handle, TOKEN_SURFACE)
    widget_set_corner_radius(handle, 8)
}

// Apply primary button style.
fn style_button_primary(handle: Int) -> Void {
    widget_set_bg_color_hex(handle, TOKEN_PRIMARY)
    widget_set_color_hex(handle, TOKEN_ON_PRIMARY)
    widget_set_corner_radius(handle, 8)
    widget_set_padding_xy(handle, 16, 8)
}

// Apply body text style to a label.
fn style_label_body(handle: Int) -> Void {
    widget_set_color_hex(handle, TOKEN_ON_BG)
    widget_set_font(handle, "system", 14, false)
}

// Apply heading style to a label.
fn style_label_heading(handle: Int) -> Void {
    widget_set_color_hex(handle, TOKEN_ON_BG)
    widget_set_font(handle, "system", 20, true)
}

// Apply muted/secondary text style.
fn style_label_muted(handle: Int) -> Void {
    widget_set_color_hex(handle, TOKEN_OUTLINE)
    widget_set_font(handle, "system", 12, false)
}
