#define BLYNK_TEMPLATE_ID "Drytch Batik Ecoprint"
#define BLYNK_TEMPLATE_NAME "Drytch Batik Ecoprint"
#define BLYNK_AUTH_TOKEN "dKteKwVbOnpkRSewlb26lBLreQunpJGG"

#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <HTTPClient.h>

const char* ssid1 = "wireless@umsida.ac.id";
const char* password1 = "AhmadDahlan1868";
const char* ssid2 = "mahasiswa@umsida.ac.id";
const char* password2 = "";
String currentSSID = "";

char auth[] = BLYNK_AUTH_TOKEN;
WiFiClient client;

#define RXD2 16
#define TXD2 17

unsigned long lastWiFiCheck = 0, lastSpeedTest = 0, lastInternetOK = 0;
bool hasEverConnected = false;

// ---------------- WIFI ----------------
void connectToWiFiAuto() {
  const int maxAttempts = 2;
  int attempt = 0;
  currentSSID = ssid1;
  while (attempt < maxAttempts) {
    Serial.println("Mencoba koneksi ke WiFi: " + currentSSID);
    WiFi.disconnect(true);
    delay(1000);
    WiFi.begin(currentSSID.c_str(), (currentSSID == ssid1) ? password1 : password2);
    unsigned long startAttemptTime = millis();
    while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 10000) {
      delay(500);
      Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("\nTerhubung ke: " + currentSSID);
      return;
    } else {
      Serial.println("\nGagal konek ke " + currentSSID);
      currentSSID = (currentSSID == ssid1) ? ssid2 : ssid1;
      attempt++;
    }
  }
}

bool testInternetSpeed() {
  HTTPClient http;
  unsigned long start = millis();
  http.begin("http://clients3.google.com/generate_204");
  int httpCode = http.GET();
  http.end();
  return (httpCode == 204 && millis() - start < 2000);
}

void handleWiFiConnection() {
  if (millis() - lastWiFiCheck < 10000) return;
  lastWiFiCheck = millis();
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi tidak terhubung, mencoba ulang...");
    connectToWiFiAuto();
    return;
  }
  if (millis() - lastSpeedTest > 30000) {
    lastSpeedTest = millis();
    if (testInternetSpeed()) {
      lastInternetOK = millis();
      hasEverConnected = true;
      Serial.println("Internet OK");
    } else {
      Serial.println("Internet lambat, ganti SSID...");
      WiFi.disconnect(true);
      delay(1000);
      currentSSID = (currentSSID == ssid1) ? ssid2 : ssid1;
      connectToWiFiAuto();
    }
  }
  if (hasEverConnected && millis() - lastInternetOK > 300000) {
    Serial.println("Restart ESP32 karena tidak ada internet 5 menit...");
    ESP.restart();
  }
}

// ---------------- BLYNK ----------------
BLYNK_WRITE(V7) { // MODE
  int mode = param.asInt();
  Serial2.println(mode == 1 ? "@#CMD#MODE#MANUAL#!" : "@#CMD#MODE#AUTO#!");
  Serial.println(mode == 1 ? "MODE MANUAL" : "MODE AUTO");
}
BLYNK_WRITE(V5) { // HEATER
  int state = param.asInt();
  Serial2.println(state == 1 ? "@#CMD#HEATER#ON#!" : "@#CMD#HEATER#OFF#!");
  Serial.println(state == 1 ? "HEATER ON" : "HEATER OFF");
}
BLYNK_WRITE(V6) { // FAN
  int state = param.asInt();
  Serial2.println(state == 1 ? "@#CMD#FAN#ON#!" : "@#CMD#FAN#OFF#!");
  Serial.println(state == 1 ? "FAN ON" : "FAN OFF");
}

// ---------------- PARSING DATA DARI ESP1 ----------------
String sData = "", data[10];
bool parsing = false, collecting = false;

void bacaSerial2() {
  while (Serial2.available()) {
    char c = Serial2.read();
    if (c == '@') { sData = ""; collecting = true; }
    if (collecting) sData += c;
    if (c == '!') { collecting = false; parsing = true; }
  }

  if (parsing) {
    parsing = false;
    Serial.println("Data: " + sData);
    int q = 0;
    for (int i = 0; i < 10; i++) data[i] = "";
    for (int i = 0; i < sData.length(); i++) {
      if (sData[i] == '#') q++;
      else data[q] += sData[i];
    }

    if (q >= 7) {
      float pv = data[1].toFloat();
      float batt = data[2].toFloat();
      float temp = data[3].toFloat();
      float hum = data[4].toFloat();
      String heater = data[5];
      String fan = data[6];
      String mode = data[7];

      Blynk.virtualWrite(V0, pv);
      Blynk.virtualWrite(V1, batt);
      Blynk.virtualWrite(V2, temp);
      Blynk.virtualWrite(V3, hum);
      Blynk.virtualWrite(V5, (heater == "ON") ? 1 : 0);
      Blynk.virtualWrite(V6, (fan == "ON") ? 1 : 0);
      Blynk.virtualWrite(V7, (mode == "MANUAL") ? 1 : 0);
    }
  }
}

// ---------------- SETUP ----------------
void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  connectToWiFiAuto();
  Blynk.config(auth);
  Blynk.connect();
  Serial.println("ESP2 Ready (Blynk + Gateway)");
}

// ---------------- LOOP ----------------
void loop() {
  handleWiFiConnection();
  if (WiFi.status() == WL_CONNECTED && !Blynk.connected()) Blynk.connect();
  Blynk.run();
  bacaSerial2();
}
