

#include <WiFi.h>
#include <PubSubClient.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <U8g2lib.h>

// === U8g2 OLED Display Configuration ===
// Uses hardware I2C with default pins (SDA=21, SCL=22) and no reset pin.
// Using the 1-page buffer constructor (_1_) to save RAM on the microcontroller.
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

// === Configuration ===
const char* ssid = "309";
const char* password = "12345678";

const char* mqtt_server = "192.168.0.122";
const char* mqtt_user = "siot";
const char* mqtt_password = "dfrobot";
const int mqtt_port = 1883;

const char* topic_env = "Enviro/air_quality";
const char* topic_cmd = "control/dev";

// === Objects ===
WiFiClient espClient;
PubSubClient client(espClient);
WebServer server(80);

// === Sensor Data Storage ===
struct {
  float temperature = 0;
  float pressure = 0;
  float humidity = 0;
  float gas = 0;
  float altitude = 0;
  int aqi = 0;
  int tvoc = 0;
  int eco2 = 0;
  bool valid = false;
} envData;

// === Batch Command Storage (Max 3 Commands) ===
const int MAX_COMMANDS = 3;
String commands[MAX_COMMANDS];
int delays[MAX_COMMANDS] = {1000, 1000, 1000}; 
int commandCount = 0;
bool batchRunning = false;
bool batchComplete = false;
String feedback[MAX_COMMANDS];

// === Function Prototypes ===
void handleRoot();
void handleControl();
void handleSendBatch();
void executeBatch();
void callback(char* topic, byte* payload, unsigned int length);
void updateOLEDStatus(bool isConnected, String ipOrMsg);

// ====================== WiFi & MQTT ======================
void setup_wifi() {
  delay(10);
  Serial.print("Connecting to "); Serial.println(ssid);
  
  // Update OLED: Inform user connection is running
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_6x10_tf);
    u8g2.drawStr(0, 12, "Connecting WiFi...");
    u8g2.drawStr(0, 28, ssid);
  } while (u8g2.nextPage());

  WiFi.begin(ssid, password);
  int retryCounter = 0;
  String dots = "";
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); 
    Serial.print(".");
    retryCounter++;
    
    if (retryCounter % 4 == 0) dots += ".";
    if (dots.length() > 6) dots = ".";

    // Animated loading dots update on OLED loop
    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_6x10_tf);
      u8g2.drawStr(0, 12, "Connecting WiFi...");
      u8g2.drawStr(0, 28, ssid);
      u8g2.drawStr(0, 44, dots.c_str());
    } while (u8g2.nextPage());
    
    if (retryCounter > 30) {
      Serial.println("\nWiFi Connection Timeout.");
      updateOLEDStatus(false, "Timeout Error");
      return;
    }
  }
  
  Serial.println("\nWiFi connected. IP: " + WiFi.localIP().toString());
  updateOLEDStatus(true, WiFi.localIP().toString());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("MQTT connecting...");
    if (client.connect("ESP32_DualWeb", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      client.subscribe(topic_env);
    } else {
      Serial.print("failed, rc="); Serial.println(client.state());
      
      if(WiFi.status() != WL_CONNECTED) {
        updateOLEDStatus(false, "WiFi Lost");
      }
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  String message;
  message.reserve(length);
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  if (String(topic) == topic_env) {
    JsonDocument doc; 
    DeserializationError error = deserializeJson(doc, message);
    if (error) {
      Serial.print("JSON parse failed: ");
      Serial.println(error.c_str());
      return;
    }

    if (doc.containsKey("temperature"))      envData.temperature = doc["temperature"];
    if (doc.containsKey("Pressure"))         envData.pressure = doc["Pressure"];
    if (doc.containsKey("Humidity"))         envData.humidity = doc["Humidity"];
    if (doc.containsKey("GasResistance"))    envData.gas = doc["GasResistance"];
    if (doc.containsKey("CalibratedAltitude")) envData.altitude = doc["CalibratedAltitude"];
    if (doc.containsKey("AQI"))              envData.aqi = doc["AQI"];
    if (doc.containsKey("TVOC"))             envData.tvoc = doc["TVOC"];
    if (doc.containsKey("ECO2"))             envData.eco2 = doc["ECO2"];

    envData.valid = true;
    Serial.println("Updated sensor data");
  }
}

