#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
const char *ssid = "iPadBerm";
const char *password = "66036603";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create an Event Source on /events
AsyncEventSource events("/events");
struct device {
  const int id;
  const int pin;
  const int btnPin;
  int prevBtnState;
  int status;  // 0:off, 1:on
};
struct device d1 = { 1, 17, 15, 0, 0 };
struct device d2 = { 2, 5, 2, 0, 0 };
struct device d3 = { 3, 18, 4, 0, 0 };
struct device d4 = { 4, 19, 16, 0, 0 };
String processor(const String &var) {
  if (var == "btn1txt") {
    return d1.status == 0 ? "ON" : "OFF";
  } else if (var == "btn2txt") {
    return d2.status == 0 ? "ON" : "OFF";
  } else if (var == "btn3txt") {
    return d3.status == 0 ? "ON" : "OFF";
  } else if (var == "btn4txt") {
    return d4.status == 0 ? "ON" : "OFF";
  } else if (var == "btn1class") {
    return d1.status == 0 ? "button" : "button2";
  } else if (var == "btn2class") {
    return d2.status == 0 ? "button" : "button2";
  } else if (var == "btn3class") {
    return d3.status == 0 ? "button" : "button2";
  } else if (var == "btn4class") {
    return d4.status == 0 ? "button" : "button2";
  }
  return String();
}
const char index_html[] PROGMEM = R"rawliteral(
  <!DOCTYPE HTML><html>
  <head>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <title>ESP32 Home Automation</title>
    <style>
    html { font-family: arial; display: inline-block; margin: 0px auto; text-align: center;}
    .button {
      background-color: mediumseagreen;
      border: none;
      color: white;
      padding: 10px 15px;
      text-decoration: none;
      font-size: 24px;
      cursor: pointer;
      margin: 3px;
    }
    .button2 {
      background-color: gray;
      border: none;
      color: white;
      padding: 10px 15px;
      text-decoration: none;
      font-size: 24px;
      cursor: pointer;
      margin: 3px;
    }
    .button3 {
      background-color: crimson;
      border: none;
      color: white;
      padding: 5px 10px;
      text-decoration: none;
      font-size: 22px;
      cursor: pointer;
      margin: 2px;
    }
    </style>
  </head>
  <body>
      <h1>ESP32 SMART Home!</h1>
      <h3 style='color: red;'\>R LED State</h3>
      <p><a href='/set?button_id=1'><button id='btn1' class='%btn1class%'>%btn1txt%</button></a></p>
      <h3 style='color: green;'>G LED State</h3>
      <p><a href='/set?button_id=2'><button id='btn2' class='%btn2class%'>%btn2txt%</button></a></p>
      <h3 style='color: blue;'>B LED State</h3>
      <p><a href='/set?button_id=3'><button id='btn3' class='%btn3class%'>%btn3txt%</button></a></p>
      <h3 style='color: orange;'>Y LED State</h3>
      <p><a href='/set?button_id=4'><button id='btn4' class='%btn4class%'>%btn4txt%</button></a></p>
      <p><a href='/reset'><button class='button3'>Reset ALL</button></a></p>
      <script>
      if (!!window.EventSource) {
        var source = new EventSource('/events');
        source.addEventListener('toggleState', function(e) {
          console.log(e.data);
          let jsonData = JSON.parse(e.data);
          const element = document.getElementById(jsonData.id);
          if(jsonData.status == 1){
            element.innerHTML = 'OFF';
            element.className = "button2";    
          }else{
            element.innerHTML = 'ON';
            element.className = "button";
          }
        }, false);
      }
</script>
</body>
</html>)rawliteral";
void setup() {
  Serial.begin(115200);
  pinMode(d1.pin, OUTPUT);
  pinMode(d2.pin, OUTPUT);
  pinMode(d3.pin, OUTPUT);
  pinMode(d4.pin, OUTPUT);
  pinMode(d1.btnPin, INPUT_PULLUP);
  pinMode(d2.btnPin, INPUT_PULLUP);
  pinMode(d3.btnPin, INPUT_PULLUP);
  pinMode(d4.btnPin, INPUT_PULLUP);
  WiFi.mode(WIFI_STA);
  //WiFi.begin(ssid, password);
  WiFi.begin("Wokwi-GUEST", "", 6);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // Set up mDNS responder: "esp32.local" to access webpage
  if (!MDNS.begin("esp32")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
  // Handle Web Server Root
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html, processor);
  });
  // Send a GET request to <IP>/set?button_id=<id>
  server.on("/set", HTTP_GET, [](AsyncWebServerRequest *request) {
    if (request->hasParam("button_id")) {
      int idValue = request->getParam("button_id")->value().toInt();
      if (idValue == d1.id) {
        togglePinState(&d1);
      } else if (idValue == d2.id) {
        togglePinState(&d2);
      } else if (idValue == d3.id) {
        togglePinState(&d3);
      } else if (idValue == d4.id) {
        togglePinState(&d4);
      }
    }
    request->send_P(200, "text/html", index_html, processor);
  });
  server.on("/reset", HTTP_GET, [](AsyncWebServerRequest *request) {
    resetAll();
    request->send_P(200, "text/html", index_html, processor);
  });
  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient *client) {
    if (client->lastId()) {
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  int newBtn1State = digitalRead(d1.btnPin);
  int newBtn2State = digitalRead(d2.btnPin);
  int newBtn3State = digitalRead(d3.btnPin);
  int newBtn4State = digitalRead(d4.btnPin);
  if (d1.prevBtnState == 1 & newBtn1State == 0) {
    Serial.println(d1.status);
    togglePinState(&d1);
  }
  if (d2.prevBtnState == 1 & newBtn2State == 0) {
    togglePinState(&d2);
  }
  if (d3.prevBtnState == 1 & newBtn3State == 0) {
    togglePinState(&d3);
  }
  if (d4.prevBtnState == 1 & newBtn4State == 0) {
    togglePinState(&d4);
  }
  d1.prevBtnState = newBtn1State;
  d2.prevBtnState = newBtn2State;
  d3.prevBtnState = newBtn3State;
  d4.prevBtnState = newBtn4State;
  delay(10);
}
void togglePinState(struct device *d) {
  if (d->status == 0) {
    digitalWrite(d->pin, HIGH);
    d->status = 1;
  } else {
    digitalWrite(d->pin, LOW);
    d->status = 0;
  }
  //Create JSON DATA as String
  char data[500];
  snprintf(data, 500, "{\"id\":\"btn%d\", \"status\":%d}", d->id, d->status);
  // Send Event to the Web Client to update button status
  events.send(data, "toggleState", millis());
}
void resetAll() {
  if (d1.status == 1) {
    togglePinState(&d1);
  }
  if (d2.status == 1) {
    togglePinState(&d2);
  }
  if (d3.status == 1) {
    togglePinState(&d3);
  }
  if (d4.status == 1) {
    togglePinState(&d4);
  }
}