#pragma once
#include <Arduino.h>
#include <Wire.h>

/**
 * @brief Драйвер оптического датчика приближения APDS-9960 (режим Proximity only).
 *
 * Поддерживает как оригинальный чип Broadcom/Avago (ID 0xAB), так и
 * распространённый на рынке клон (ID 0xA8) — оба варианта считаются
 * успешным подключением, реальный найденный ID доступен через getDeviceId().
 * ALS/RGB и Gesture не реализованы: клоны нестабильно поддерживают эти режимы.
 */
class Apds9960 {
public:
    explicit Apds9960(TwoWire &wire = Wire);

    /**
     * @brief Инициализирует шину I2C и включает proximity-движок датчика.
     * @param sda Пин SDA.
     * @param scl Пин SCL.
     * @return false, если чип не отвечает на шине (ошибка I2C-транзакции).
     *         true, если чип ответил — даже с неопознанным ID (см. getDeviceId()).
     */
    bool begin(uint8_t sda, uint8_t scl);

    /**
     * @brief Читает сырое значение proximity (регистр PDATA, без фильтрации и калибровки).
     * @param outValue Куда записать результат, диапазон 0-255.
     * @return false при ошибке I2C-транзакции (outValue не изменяется).
     */
    bool readProximity(uint8_t &outValue);

    /** @brief Возвращает ID устройства, прочитанный при begin() (0, если begin() не вызывался/не удался). */
    uint8_t getDeviceId() const;

    /**
     * @brief Проверяет, что были недавние успешные обмены с датчиком по шине.
     * @param timeoutMs Максимально допустимый возраст последнего успешного обмена, мс.
     */
    bool isAlive(unsigned long timeoutMs = 500) const;

private:
    // Регистры и адрес — датащит Broadcom/Avago APDS-9960, AV02-4191EN, "Register Descriptions".
    static constexpr uint8_t kAddress          = 0x39; // I2C device address (7-bit)
    static constexpr uint8_t kRegEnable        = 0x80; // ENABLE: бит0 PON, бит2 PEN
    static constexpr uint8_t kRegPPulse        = 0x8E; // PPULSE: длительность/число ИК-импульсов
    static constexpr uint8_t kRegControlOne    = 0x8F; // CONTROL: PGAIN, AGAIN, LDRIVE
    static constexpr uint8_t kRegId            = 0x92; // ID: идентификатор чипа
    static constexpr uint8_t kRegProximityData = 0x9C; // PDATA: результат proximity, 8 бит

    static constexpr uint8_t kEnablePonPen     = 0x05; // PON=1 (бит0) + PEN=1 (бит2)
    static constexpr uint8_t kPPulseDefault    = 0x10; // 16 импульсов, длительность 4us (значение из практики клонов)
    static constexpr uint8_t kControlDefault   = 0xD0; // LDRIVE=12.5мА, PGAIN=x5 (значение из практики клонов)

    // Задержка "прогрева" после включения PON — не взята из даташита напрямую
    // (там указаны только тайминги ADC-цикла), а подобрана эмпирически с запасом
    // для устойчивого старта у клонов. См. THEORY.md, раздел про калибровку.
    static constexpr uint16_t kPowerOnWarmupMs = 200;

    static constexpr uint8_t kIdOriginal    = 0xAB; // оригинал Broadcom/Avago
    static constexpr uint8_t kIdCloneKnown  = 0xA8; // распространённый клон на рынке

    TwoWire *_wire;
    uint8_t _deviceId = 0;
    unsigned long _lastOkMs = 0;

    bool writeRegister(uint8_t reg, uint8_t value);
    bool readRegister(uint8_t reg, uint8_t &outValue);
};
