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

/**
 * @brief Драйвер цифрового MEMS-микрофона ICS-43434 (интерфейс I2S, 24 бита, ESP-IDF 5 / Arduino Core 3.x).
 * Инкапсулирует настройку канала I2S в режиме приёма (RX), чтение блока сэмплов через DMA
 * и перевод сырого 24-битного слова в 16-битный знаковый отсчёт.
 *
 * @note Электрически и по протоколу ICS-43434 — близкий аналог INMP441 (тот же формат I2S,
 * 24 значащих бита в 32-битном слове, тот же принцип выбора канала через пин L/R). Отдельный
 * класс, а не переиспользование Inmp441, — по стандарту компонента "один класс на компонент";
 * оба класса совпадают почти дословно потому, что протокол I2S у обоих микрофонов один и тот
 * же, а не потому, что это один и тот же чип.
 */
class Ics43434 {
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_5;     ///< Serial Clock (BCLK/SCK)
        gpio_num_t ws_pin = GPIO_NUM_18;     ///< Word Select (LRCLK/WS)
        gpio_num_t sd_pin = GPIO_NUM_19;     ///< Serial Data (SD/DOUT микрофона → DIN ESP32)
        i2s_port_t i2s_port = I2S_NUM_0;     ///< Номер периферийного блока I2S
        uint32_t sample_rate = 44100;        ///< Частота дискретизации, Гц (аудио-стандарт — см. THEORY.md)
        Channel channel = Channel::Left;     ///< Слот, в котором микрофон передаёт данные (пин L/R, обычно SEL)
    };

    explicit Ics43434(const Config& config);
    Ics43434() : Ics43434(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-битный знаковый отсчёт.
     * ICS-43434 передаёт 24 значащих бита, выровненных по старшим разрядам 32-битного слова:
     * [24 бита данных][8 нулевых бит]. Сдвиг на 16 бит одновременно отбрасывает 8 нулевых бит и
     * младшие 8 бит данных, оставляя старшие 16 бит — этого разрешения достаточно для librosa/FFT.
     */
    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;
};
