// p5_morse.h — Morse / telegraph-key puzzle driver for Zacus master (P5).
//
// When CONFIG_ZACUS_P5_MORSE_ENABLE=n (default) all functions are empty stubs
// (init returns ESP_OK, arm/disarm are no-ops) so callers need no #ifdef guards.
//
// When enabled:
//   1. Call p5_morse_init() once at boot (after gpio driver is available).
//   2. Call p5_morse_arm(expected, puzzle_id, fragment, frag_len) when the
//      gateway POSTs /game/step with a "morse" puzzle.
//   3. A FreeRTOS task decodes dot/dash timing on CONFIG_ZACUS_P5_GPIO and
//      calls the solved_cb supplied to p5_morse_arm() when the decoded word
//      matches `expected`.
//   4. Call p5_morse_disarm() on step change or game reset.
//
// Timing constants are set via Kconfig (DOT_MS, DASH_MS, GAP_MS).
// The key is active-LOW by default (CONFIG_ZACUS_P5_ACTIVE_LOW=y).

#pragma once

#include "esp_err.h"
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// Callback type invoked on the p5_morse task when the sequence is solved.
// Must be ISR-safe in the sense that it runs inside the morse task context;
// do NOT call p5_morse_arm/disarm from it — defer via a task notification.
typedef void (*p5_morse_solved_cb_t)(void);

/**
 * @brief Initialise the P5 Morse puzzle driver.
 *
 * Configures CONFIG_ZACUS_P5_GPIO as input with pull-up and spawns the
 * morse decoding task (blocked until p5_morse_arm() is called).
 * Idempotent — safe to call more than once.
 *
 * When CONFIG_ZACUS_P5_MORSE_ENABLE=n returns ESP_OK immediately.
 *
 * @return ESP_OK on success, or a driver error code.
 */
esp_err_t p5_morse_init(void);

/**
 * @brief Arm the morse puzzle for a specific expected sequence.
 *
 * @param expected   NUL-terminated Morse code string to match,
 *                   e.g. "...-" (upper-case letters via kMorseTable)
 *                   OR a plain word like "ZACUS" (decoded internally).
 *                   The string is copied — caller buffer may be transient.
 * @param solved_cb  Callback invoked exactly once when the sequence matches.
 *                   Pass NULL to skip the notification (e.g. during tests).
 *
 * When CONFIG_ZACUS_P5_MORSE_ENABLE=n this is a no-op.
 */
void p5_morse_arm(const char *expected, p5_morse_solved_cb_t solved_cb);

/**
 * @brief Disarm the puzzle (stop decoding, reset state).
 *
 * When CONFIG_ZACUS_P5_MORSE_ENABLE=n this is a no-op.
 */
void p5_morse_disarm(void);

#ifdef __cplusplus
}
#endif
