// local_puzzles.c — wires QR/sound to puzzle_state and arms by puzzle id.
#include "local_puzzles.h"
#include "qr_puzzle.h"
#include "sound_puzzle.h"
#include <string.h>

static puzzle_state_t *s_state;

// Per-type static contexts — copied at arm time so caller buffers can be
// transient (e.g. a REST handler's stack frame).
typedef struct {
    uint8_t id;
    uint8_t frag[PUZZLE_MAX_FRAG];
    uint8_t frag_len;
} puzzle_ctx_t;

static puzzle_ctx_t s_qr_ctx;
static puzzle_ctx_t s_sound_ctx;

static void on_qr_solved(void) {
    puzzle_state_report(s_state, s_qr_ctx.id, s_qr_ctx.frag, s_qr_ctx.frag_len);
}

static void on_sound_solved(void) {
    puzzle_state_report(s_state, s_sound_ctx.id, s_sound_ctx.frag, s_sound_ctx.frag_len);
}

void local_puzzles_init(puzzle_state_t *state) { s_state = state; }

esp_err_t local_puzzles_arm_qr(uint8_t puzzle_id,
                               const char *const *expected, size_t count,
                               const uint8_t *fragment, uint8_t frag_len) {
    if (!s_state) return ESP_ERR_INVALID_STATE;
    if (puzzle_id < 1 || puzzle_id > PUZZLE_MAX_ID) return ESP_ERR_INVALID_ARG;
    if (frag_len > PUZZLE_MAX_FRAG) return ESP_ERR_INVALID_ARG;
    if (frag_len > 0 && fragment == NULL) return ESP_ERR_INVALID_ARG;

    if (qr_puzzle_is_running()) return ESP_ERR_INVALID_STATE;

    puzzle_ctx_t prev_qr = s_qr_ctx;
    s_qr_ctx.id       = puzzle_id;
    s_qr_ctx.frag_len = frag_len;
    if (frag_len > 0) {
        memcpy(s_qr_ctx.frag, fragment, frag_len);
    }
    esp_err_t e = qr_puzzle_start(expected, count, on_qr_solved);
    if (e != ESP_OK) { s_qr_ctx = prev_qr; }
    return e;
}

esp_err_t local_puzzles_arm_sound(uint8_t puzzle_id,
                                  const int *expected, size_t count, int tol,
                                  const uint8_t *fragment, uint8_t frag_len) {
    if (!s_state) return ESP_ERR_INVALID_STATE;
    if (puzzle_id < 1 || puzzle_id > PUZZLE_MAX_ID) return ESP_ERR_INVALID_ARG;
    if (frag_len > PUZZLE_MAX_FRAG) return ESP_ERR_INVALID_ARG;
    if (frag_len > 0 && fragment == NULL) return ESP_ERR_INVALID_ARG;

    if (sound_puzzle_is_running()) return ESP_ERR_INVALID_STATE;

    s_sound_ctx.id       = puzzle_id;
    s_sound_ctx.frag_len = frag_len;
    if (frag_len > 0) {
        memcpy(s_sound_ctx.frag, fragment, frag_len);
    }
    sound_puzzle_start(expected, count, tol, on_sound_solved);
    return ESP_OK;
}

void local_puzzles_disarm(void) {
    qr_puzzle_stop();
    sound_puzzle_stop();
}
