// cmd_exec.h — BOX-3 executor for structured ESP-NOW CMD frames (D5 contract).
//
// Wire format (SCENARIO_MESH_TEXT_CMD, ≤200 bytes):
//   {"op":"<verb>","a":{<args>}}
//
// Supported ops:
//   screen  {"t":"title","u":"subtitle","y":"symbol","e":"effect"} — display on LCD
//             effect: "pulse"|"glitch"|"gyro"|"none"
//   play    {"p":"<path>","l":0|1} — stream WAV via I2S; embedded cue if no file
//   evt     {"n":"<name>"}         — log the event (future: relay to master)
//   led     {"p":"<pattern>"}      — log the pattern (stub)
//   <any>   unknown op             — log warn, ignore
//
// Tolerant by design: malformed JSON, missing keys, or unknown ops log a warning
// and return without crashing. Never asserts on network input.

#pragma once

#include <stddef.h>
#include "esp_err.h"
#include "driver/i2s_std.h"

#ifdef __cplusplus
extern "C" {
#endif

// Parse and execute one CMD frame. `data` is the raw UTF-8 payload received via
// scenario_mesh text callback (NUL-terminated). Returns ESP_OK if the op was
// recognised and dispatched, ESP_ERR_INVALID_ARG on bad JSON or missing `op`,
// ESP_ERR_NOT_SUPPORTED for unknown ops (all logged, no crash).
esp_err_t cmd_exec_handle(const char *data, size_t len);

// Provide the speaker I2S channel handle so exec_play() can stream audio.
// Must be called from main.c after speaker_init(), before any CMD arrives.
void cmd_exec_set_spk_handle(i2s_chan_handle_t h);

#ifdef __cplusplus
}
#endif
