#pragma once
#include <Arduino.h>

/**
 * @brief Драйвер PIR-датчика движения AM312 (пассивный ИК, цифровой выход).
 * В отличие от HMMD mmWave (см. ../HMMD-mmWave) — не радар: не излучает ничего сам, а только
 * пассивно ловит изменение теплового ИК-излучения в поле зрения. Поэтому видит только
 * ДВИЖЕНИЕ — неподвижный, пусть даже тёплый человек, для него невидим. Подробности в THEORY.md.
 *
 * @note У AM312 нет UART и нет команд настройки — это простой цифровой выход (HIGH = движение
 * в последние ~2-3 сек, LOW = покой), читается через прерывание по фронту. Драйвер ничего не
 * калибрует программно: у датчика нет интерфейса для этого, физическая стабилизация после
 * подачи питания — единственное, что нужно выждать (см. @note warmup ниже и THEORY.md).
 */
class PirSensor {
public:
    /// Текущее состояние датчика движения.
    struct Data {
        bool motionActive = false;      ///< true, пока движение числится активным (с учётом hold time)
        uint32_t lastMotionDurationMs = 0;  ///< Длительность предыдущего эпизода движения, мс
    };

    /**
     * @param pin GPIO, подключённый к выходу OUT датчика (см. WIRING.md)
     * @param holdTimeMs Через сколько мс без нового фронта считать, что движение закончилось
     * @param debounceMs Минимальный интервал между засчитываемыми фронтами — защита от дребезга
     */
    explicit PirSensor(uint8_t pin, uint32_t holdTimeMs = 2000, uint32_t debounceMs = 50);

    /// Настраивает пин и прерывание. Не блокирует и ничего не калибрует на самом датчике.
    void begin();

    /// Считать состояние прерывания и обновить Data (учитывая hold time). Вызывать в каждой итерации loop().
    void update();

    /// Последнее известное состояние движения.
    const Data& getData() const { return _data; }

    /**
     * @brief Прошло ли ещё время прогрева датчика после begin().
     * @note AM312 не имеет команды "калибровка" — это фиксированный аналоговый датчик. Но сразу
     * после подачи питания пироэлектрический элемент ещё не стабилизировался и может давать
     * ложные срабатывания в течение нескольких секунд (по опыту применения подобных PIR-модулей,
     * не задокументировано численно производителем для этой конкретной модели) — см. THEORY.md.
     * Это не блокирующая задержка: update() продолжает работать всё это время, warmup — только
     * информационный флаг для тестового стенда, не подавляет события.
     * @param warmupMs Сколько мс после begin() считать датчик прогревающимся.
     */
    bool isWarmingUp(uint32_t warmupMs = 5000) const;

private:
    static void IRAM_ATTR handleInterrupt();

    static volatile bool _intrFired;
    static volatile uint32_t _intrTimeMs;
    static PirSensor* _instance;

    uint8_t _pin;
    uint32_t _holdTimeMs;
    uint32_t _debounceMs;

    Data _data;
    uint32_t _lastEventMs = 0;
    uint32_t _motionStartMs = 0;
    uint32_t _beginMs = 0;
};
