/**
 * DreamStack Panel IR Runtime — LVGL Widget Builder
 *
 * Parses Panel IR JSON and creates LVGL widgets.
 * Handles signal binding, text template expansion,
 * event dispatch, and timer execution.
 *
 * This is the C equivalent of the browser-based panel previewer.
 */

#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"

// ─── Limits ───
#define DS_MAX_SIGNALS   64
#define DS_MAX_NODES     128
#define DS_MAX_TIMERS    8
#define DS_MAX_BINDINGS  64

// ─── Signal types ───
typedef enum {
    DS_SIG_INT = 0,
    DS_SIG_BOOL,
    DS_SIG_STRING,
} ds_sig_type_t;

// ─── Signal value ───
typedef struct {
    int32_t       i;        // integer value (also used for bool: 0/1)
    char          s[32];    // string value (short strings only)
    ds_sig_type_t type;
    bool          used;
} ds_signal_t;

// ─── Timer entry ───
typedef struct {
    uint32_t    ms;         // interval in milliseconds
    uint8_t     action_op;  // action opcode
    uint16_t    action_sig; // target signal
    int32_t     action_val; // value for set/add/sub
    void       *timer;      // LVGL timer handle (lv_timer_t *)
} ds_timer_t;

// ─── Action callback (for forwarding to ESP-NOW) ───
typedef void (*ds_action_cb_t)(uint8_t node_id, uint8_t action_type);

/**
 * Initialize the Panel IR runtime.
 * Must be called after LVGL is initialized.
 *
 * @param parent     LVGL parent object (usually lv_scr_act())
 * @param action_cb  Callback for widget actions (forwarded to ESP-NOW)
 */
esp_err_t ds_runtime_init(void *parent, ds_action_cb_t action_cb);

/**
 * Build the UI from Panel IR JSON.
 * Parses the JSON, creates LVGL widgets, binds signals.
 * Destroys any previously built UI first.
 *
 * @param ir_json  Panel IR JSON string
 * @param length   Length of the JSON string
 */
esp_err_t ds_ui_build(const char *ir_json, size_t length);

/**
 * Destroy the current UI tree.
 * Removes all LVGL widgets and clears signal bindings.
 */
void ds_ui_destroy(void);

/**
 * Update a signal value and refresh bound widgets.
 *
 * @param signal_id  Signal ID (0-based)
 * @param value      New integer value
 */
void ds_signal_update(uint16_t signal_id, int32_t value);

/**
 * Get current signal count.
 */
uint16_t ds_signal_count(void);

/**
 * Get signal value by ID.
 */
int32_t ds_signal_get(uint16_t signal_id);
