#pragma once

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

/*
	Конфигурация датчика освещённости BH1750.
*/
struct Bh1750Config {
	uint8_t sda_pin = 16;
	uint8_t scl_pin = 17;
	uint8_t i2c_address = 0x5C;

	/*
		Режим измерения:
		0x10 = Continuous High Resolution Mode
		Это самый удобный стартовый режим.
	*/
	uint8_t measurement_mode = 0x10;

	/*
		Через сколько миллисекунд без успешного чтения считать данные устаревшими.
	*/
	uint32_t stale_after_ms = 2000;

	/*
		Интервал между попытками чтения.
		Для continuous mode слишком часто дёргать датчик не нужно.
	*/
	uint32_t read_interval_ms = 200;

	/*
		EMA-фильтр для сглаживания.
		0.0 -> почти без обновления
		1.0 -> без сглаживания
	*/
	float lux_ema_alpha = 0.25f;

	/*
		Максимальное значение lux, соответствующее level=10 и percent=100.
		BH1750 в High Resolution Mode выдаёт до ~65535 lux (прямой солнечный свет).
		Для офиса / квартиры разумный потолок — 1000 lux.
		Откалибруйте под условия эксплуатации.
	*/
	float lux_max = 1000.0f;
};

/*
	Драйвер / обёртка для BH1750 без внешних библиотек.
*/
class Bh1750Sensor {
public:
	Bh1750Sensor();

	/*
		Инициализация I2C и перевод датчика в рабочий режим.
	*/
	bool begin(const Bh1750Config &config);

	/*
		Периодическое обновление состояния датчика.
		Нужно вызывать часто из loop().
	*/
	void update();

	/*
		Последнее сырое значение lux без фильтра.
	*/
	float get_raw_lux() const;

	/*
		Последнее сглаженное значение lux.
	*/
	float get_filtered_lux() const;

	/*
		Уровень освещения 0..10 (относительно lux_max).
	*/
	uint8_t get_level() const;

	/*
		Уровень освещения в процентах 0..100 (относительно lux_max).
	*/
	uint8_t get_percent() const;

	/*
		Есть ли валидные данные.
	*/
	bool has_valid_data() const;

	/*
		Не устарели ли данные.
	*/
	bool is_stale() const;

	/*
		Доступен ли датчик.
	*/
	bool is_online() const;

	/*
		JSON состояния датчика.
		Формат:
		{
		  "online":  true,
		  "level":   4,
		  "lux":     160.15,
		  "percent": 11
		}
	*/
	String get_state_json() const;

private:
	Bh1750Config _config;

	bool _initialized = false;
	bool _online = false;
	bool _has_valid_data = false;

	uint32_t _last_read_attempt_ms = 0;
	uint32_t _last_success_read_ms = 0;

	uint16_t _last_raw_value = 0;
	float _raw_lux = 0.0f;
	float _filtered_lux = 0.0f;

private:
	bool send_command(uint8_t command);
	bool read_measurement(uint16_t &raw_out);
	void update_filtered_lux(float new_lux);
};