#include <ETH.h>
#include <WiFiUdp.h>
#include <SNMP_Agent.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <string>

// ======================================================================
// NETWORK
// ======================================================================
WiFiUDP udp;
#define SNMP_PORT 161

// ======================================================================
// SNMP AGENT
// ======================================================================
SNMPAgent snmp("public", "private");

// ======================================================================
// SENSOR
// ======================================================================
Adafruit_BME280 bme;
bool sensor_present = false;

// ======================================================================
// SNMP DATA (Gauge32 – Domotz compatible)
// ======================================================================
uint32_t temperature_x10 = 0;   // °C ×10
uint32_t humidity_x10    = 0;   // %RH ×10
uint32_t pressure_x10    = 0;   // hPa ×10
uint32_t sensor_status   = 0;   // 1 = OK, 0 = Fault

// ======================================================================
// STANDARD MIB-II
// ======================================================================
uint32_t sysUpTimeTicks = 0;
std::string sysDescr = "OneSchool ESP32 Environmental Sensor (BME280)";
std::string sysName  = "RSO-IT-Rack-Sensor";

// ======================================================================
// SETUP
// ======================================================================
void setup() {
  Serial.begin(115200);
  delay(1500);
  Serial.println("\n=== ESP32 SNMP ENV SENSOR (DOMOTZ SAFE) ===");

  // ---------------- I2C ----------------
  Wire.begin(7, 8);  // SDA, SCL
  Wire.setClock(400000);

  // ---------------- BME280 ----------------
  Serial.println("Initialising BME280...");
  if (bme.begin(0x76) || bme.begin(0x77)) {
    Serial.println("BME280 detected");
    sensor_present = true;

    bme.setSampling(
      Adafruit_BME280::MODE_FORCED,
      Adafruit_BME280::SAMPLING_X2,
      Adafruit_BME280::SAMPLING_X1,
      Adafruit_BME280::SAMPLING_X1,
      Adafruit_BME280::FILTER_OFF,
      Adafruit_BME280::STANDBY_MS_500
    );
  } else {
    Serial.println("ERROR: BME280 not detected");
    sensor_present = false;
  }

  // ---------------- Ethernet ----------------
  Serial.println("Starting Ethernet...");
  ETH.begin();   // Ethernet availability does NOT gate logic

  // ---------------- SNMP ----------------
  udp.begin(SNMP_PORT);
  snmp.setUDP(&udp);

  // -------- Enterprise OIDs (Gauge32) --------
  snmp.addGaugeHandler(".1.3.6.1.4.1.49701.1.0", &temperature_x10);
  snmp.addGaugeHandler(".1.3.6.1.4.1.49701.1.1", &humidity_x10);
  snmp.addGaugeHandler(".1.3.6.1.4.1.49701.1.2", &pressure_x10);
  snmp.addGaugeHandler(".1.3.6.1.4.1.49701.1.99", &sensor_status);

  // -------- Standard SNMP OIDs --------
  snmp.addReadOnlyStaticStringHandler(".1.3.6.1.2.1.1.1.0", sysDescr);
  snmp.addGaugeHandler(".1.3.6.1.2.1.1.3.0", &sysUpTimeTicks);
  snmp.addReadOnlyStaticStringHandler(".1.3.6.1.2.1.1.5.0", sysName);

  snmp.begin();
  Serial.println("SNMP agent started (UDP/161)");
}

// ======================================================================
// LOOP – RUNS EVEN WITHOUT ETHERNET
// ======================================================================
void loop() {
  snmp.loop();
  sysUpTimeTicks = millis() / 10;

  sensor_status = 0;  // pessimistic default

  if (sensor_present) {
    bme.takeForcedMeasurement();

    float t = bme.readTemperature();
    float h = bme.readHumidity();
    float p = bme.readPressure() / 100.0;

    if (!isnan(t) && !isnan(h) && !isnan(p)) {
      temperature_x10 = (uint32_t)(t * 10);
      humidity_x10    = (uint32_t)(h * 10);
      pressure_x10    = (uint32_t)(p * 10);
      sensor_status   = 1;

      Serial.printf(
        "Temp: %.1f°C | Hum: %.1f%% | Press: %.1fhPa | STATUS: OK\n",
        t, h, p
      );
    } else {
      Serial.println("Sensor read failed | STATUS: FAULT");
    }
  } else {
    Serial.println("Sensor missing | STATUS: FAULT");
  }

  delay(2000);
}