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

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    char step_id[64];        // current scenario step ("" = none)
    char armed[8];           // "qr" | "sound" | "none"
    char code[16];           // assembled puzzle code
    uint8_t solved_count;
    char ip[16];             // STA IP ("" = none)
    bool wake_active;        // wake-word detector up

    // Scene metadata (from the step's optional `scene` IR object; empty
    // strings = fall back to step_id / armed / code). Sizes mirror
    // puzzle_binding.h SB_MAX_*.
    char scene_title[48];
    char scene_subtitle[64];
    char scene_symbol[16];
    uint8_t scene_effect;    // scene_effect_t value (0=pulse 1=glitch 2=gyro 3=none)
} display_status_t;

/**
 * @brief Initialise the ST7796 panel via LovyanGFX and show a splash screen.
 *
 * Must be called once from app_main after NVS init but before the idle loop.
 * Non-fatal: a failure is logged and the rest of the firmware continues.
 * The internal refresh task is spawned here; it polls for status changes
 * every 250 ms.
 *
 * @return ESP_OK on success, or a driver error code.
 */
esp_err_t display_ui_init(void);

/**
 * @brief Copy a new status snapshot and request an async redraw.
 *
 * Thread-safe. The copy is protected by an internal mutex; the actual
 * rendering happens on the display task (LovyanGFX is not thread-safe
 * across tasks).
 *
 * @param s  Pointer to the caller's status struct.  May be NULL (no-op).
 */
void display_ui_set_status(const display_status_t *s);

/**
 * @brief Set the backlight brightness (LEDC PWM on LEDC_TIMER_1/CHANNEL_1).
 *
 * @param pct  0..100 (values above 100 are clamped). Default after init: 100.
 */
void display_ui_set_brightness(uint8_t pct);

/**
 * @brief Push a camera frame for the scene-view viewfinder (QR aiming aid).
 *
 * Thread-safe; intended as the qr_puzzle preview callback (wired in main.c).
 * Copies the grayscale QVGA buffer; the display task converts it to RGB565
 * and refreshes the canvas at ~5 fps. Frames are shown only while the scene
 * view is active with the QR puzzle armed. Non-QVGA frames are ignored.
 */
void display_ui_camera_frame(const uint8_t *gray, int width, int height);

/**
 * @brief Handle a 5-way key press (called from the buttons scan task).
 *
 * Original key numbering: 1=SELECT 2=DOWN 3=MENU 4=LEFT/RIGHT 5=UP.
 * Shell closed: SELECT / LEFT-RIGHT toggle scene↔status; MENU opens the
 * Workbench shell; UP/DOWN step the backlight brightness.
 * Shell open: grid navigation per the original ui_amiga_shell semantics
 * (SELECT launches the tile — Statut / Scene / Auto / Lumiere; MENU closes).
 * Thread-safe (atomic request flags consumed by the display task; the
 * brightness path drives LEDC directly, which has its own locking).
 */
void display_ui_handle_key(uint8_t key);

/**
 * @brief Pop the pending shell-app launch request, if any.
 *
 * Dynamic shell tiles (from /littlefs/apps/<id>/) set a pending launch on
 * SELECT; the main loop polls this and performs the app action (e.g. read
 * the app's step.txt and call game_endpoint_apply_step). One-shot: returns
 * true at most once per launch.
 */
bool display_ui_take_pending_launch(char *id_out, size_t cap);

#ifdef __cplusplus
}
#endif
