#pragma once
#include <Arduino.h>
#include <driver/i2s_std.h>

/**
 * @brief Драйвер цифрового MEMS-микрофона INMP441 (интерфейс I2S, 24 бита, ESP-IDF 5 / Arduino Core 3.x).
 * Инкапсулирует настройку канала I2S в режиме приёма (RX), чтение блока сэмплов через DMA
 * и перевод сырого 24-битного слова в 16-битный знаковый отсчёт.
 */
class Inmp441 {
public:
    /// Какой стереослот занимает микрофон на шине I2S — определяется пином L/R (см. WIRING.md).
    enum class Channel : uint8_t {
        Left,  ///< L/R подключен к GND (стандартная распайка большинства модулей)
        Right  ///< L/R подключен к VDD/3.3V
    };

    /// Конфигурация интерфейса I2S. Значения по умолчанию рассчитаны на ESP32 DevKit v1 (см. WIRING.md).
    struct Config {
        gpio_num_t bck_pin = GPIO_NUM_26;    ///< Serial Clock (BCLK/SCK)
        gpio_num_t ws_pin = GPIO_NUM_25;     ///< Word Select (LRCLK/WS)
        gpio_num_t sd_pin = GPIO_NUM_32;     ///< Serial Data (SD/DOUT микрофона → DIN ESP32)
        i2s_port_t i2s_port = I2S_NUM_0;     ///< Номер периферийного блока I2S
        uint32_t sample_rate = 16000;        ///< Частота дискретизации, Гц (16 кГц — стандарт для голоса)
        Channel channel = Channel::Left;     ///< Слот, в котором микрофон передаёт данные (пин L/R)
    };

    explicit Inmp441(const Config& config);
    Inmp441() : Inmp441(Config()) {}

    /**
     * @brief Инициализация канала I2S и GPIO. Вызвать один раз в setup().
     * @return true, если канал создан, настроен на стандарт Philips (I2S_STD) и запущен.
     */
    [[nodiscard]] bool begin();

    /**
     * @brief Блокирующее чтение блока сэмплов из DMA-буфера I2S.
     * @param buffer Буфер под сырые 32-битные слова (в каждом полезны старшие 24 бита).
     * @param sample_count Размер buffer в сэмплах (НЕ в байтах).
     * @param samples_read Сколько сэмплов реально прочитано.
     * @param timeout_ms Максимальное время ожидания данных от DMA.
     * @return ESP_OK при успехе; код ошибки ESP-IDF иначе (см. begin() — канал мог не запуститься).
     */
    esp_err_t read(int32_t* buffer, size_t sample_count, size_t* samples_read, uint32_t timeout_ms = 100);

    /**
     * @brief Перевод сырого 32-битного слова I2S в 16-битный знаковый отсчёт.
     * INMP441 передаёт 24 значащих бита, выровненных по старшим разрядам 32-битного слова
     * (формат I2S_DATA_BIT_WIDTH_32BIT + MSB-выравнивание): [24 бита данных][8 нулевых бит].
     * Сдвиг на 16 бит одновременно отбрасывает 8 нулевых бит и младшие 8 бит данных,
     * оставляя старшие 16 бит — этого разрешения достаточно для Serial Plotter и FFT в Python.
     */
    static inline int16_t toSample16(int32_t raw_word) {
        return static_cast<int16_t>(raw_word >> 16);
    }

    /**
     * @brief Вотчдог связи с DMA-каналом I2S.
     * @param timeoutMs Через сколько мс без единого успешного read() считать канал мёртвым.
     * @return true, если за последние timeoutMs было хотя бы одно успешное чтение (или чтений ещё не было).
     */
    bool isAlive(unsigned long timeoutMs = 500) const;

    uint32_t getSampleRate() const { return _config.sample_rate; }

private:
    Config _config;
    i2s_chan_handle_t _rxHandle = nullptr;
    unsigned long _lastOkMs = 0;
};
