//#include "TrimiteMail.h"
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
//#include <ESP32_MailClient.h>
#include "ConectareWiFi.h"
#include "ThingSpeak.h"
#include <AsyncElegantOTA.h>


//#include <Adafruit_Sensor.h>
//#include <Adafruit_BME280.h>


//#define SEALEVELPRESSURE_HPA (1024)
//Adafruit_BME280 bme; // I2C

WiFiClient  client_temp;


#define CHANNEL_ID 1304041
#define CHANNEL_API_KEY ""


void sendCallback(SendStatus);

unsigned long           stopWIFI;
bool                    conectat = false;


// To send Email using Gmail use port 465 (SSL) and SMTP Server smtp.gmail.com
// YOU MUST ENABLE less secure app option https://myaccount.google.com/lesssecureapps?pli=1

#define emailSenderAccount    "[email protected]"
#define emailSenderPassword   ""
#define smtpServer            "smtp.gmail.com"
#define smtpServerPort        465
#define emailSubject          "[ATENTIE] Modificare de temperatura"

// Default Recipient Email Address
String inputMessage = "[email protected]";
String enableEmailChecked = "checked";
String inputMessage2 = "true";
// Default Threshold Temperature Value
String inputMessage3 = "25.0";
String lastTemperature;

// HTML web page to handle 3 input fields (email_input, enable_email_input, threshold_input)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>Email Notification with Temperature</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head><body>
  <h2>Temperatura la sediul PENTAGON</h2> 
  <h3>%TEMPERATURE% &deg;C</h3>
  <h2>Notificare prin email</h2>
  <form action="/get">
    Adresa de email <input type="email" name="email_input" value="%EMAIL_INPUT%" required><br>
    Activeaza Notificarea pe emaillllll <input type="checkbox" name="enable_email_input" value="true" %ENABLE_EMAIL%><br>
    Pragul de temperatura <input type="number" step="0.1" name="threshold_input" value="%THRESHOLD%" required><br>
    <input type="submit" value="Trimite">
  </form>
</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Nu am gasit");
}

AsyncWebServer server(80);

// Replaces placeholder with DS18B20 values
String processor(const String& var){
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return lastTemperature;
  }
  else if(var == "EMAIL_INPUT"){
    return inputMessage;
  }
  else if(var == "ENABLE_EMAIL"){
    return enableEmailChecked;
  }
  else if(var == "THRESHOLD"){
    return inputMessage3;
  }
  return String();
}

// Flag variable to keep track if email notification was sent or not
bool emailSent = false;

const char* PARAM_INPUT_1 = "email_input";
const char* PARAM_INPUT_2 = "enable_email_input";
const char* PARAM_INPUT_3 = "threshold_input";

// Interval between sensor readings. Learn more about timers: https://RandomNerdTutorials.com/esp32-pir-motion-sensor-interrupts-timers/
unsigned long previousMillis = 0;     
const long interval = 60000;    

// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;     
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor 
DallasTemperature sensors(&oneWire);

// The Email Sending data object contains config and data to send
SMTPData smtpData;

//bool ERR_BME;

void setup() {
  Serial.begin(9600);
//  bool status;
//  ERR_BME = false;
//  status = bme.begin(0x76);
//  if (!status) {
//      ERR_BME = true;
//  }

//  btStop();
//  ConectareWifi(192,168,1,200);
  ConectareWifi(192,168,0,121);
//  ConectareWifi(192,168,1,121);
  Serial.println();
  Serial.print("ESP IP Address: http://");
  Serial.println(WiFi.localIP());
  
  // Start the DS18B20 sensor
  sensors.begin();

  // Send web page to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Receive an HTTP GET request at <ESP_IP>/get?email_input=<inputMessage>&enable_email_input=<inputMessage2>&threshold_input=<inputMessage3>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    // GET email_input value on <ESP_IP>/get?email_input=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      // GET enable_email_input value on <ESP_IP>/get?enable_email_input=<inputMessage2>
      if (request->hasParam(PARAM_INPUT_2)) {
        inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
        enableEmailChecked = "checked";
      }
      else {
        inputMessage2 = "false";
        enableEmailChecked = "";
      }
      // GET threshold_input value on <ESP_IP>/get?threshold_input=<inputMessage3>
      if (request->hasParam(PARAM_INPUT_3)) {
        inputMessage3 = request->getParam(PARAM_INPUT_3)->value();
      }
    }
    else {
      inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    Serial.println(inputMessage2);
    Serial.println(inputMessage3);
    request->send(200, "text/html", "Modificarea a fost transmisa.<br><a href=\"/\">Intoarcere la pagina principala</a>");
  });
  server.onNotFound(notFound);
  AsyncElegantOTA.begin(&server, "lroman", "flexiblebird97");    // Activeaza functionalitatea de actualizare de la distanta a firmware-ului sistemului.
  server.begin();
  ThingSpeak.begin(client_temp);
  ThingSpeak.writeField(CHANNEL_ID, 2, 1, CHANNEL_API_KEY);

  String emailMessage = String("Serverul de temperatura a re-pornit, posibil din cauza unei caderi de tensiune");
  if(sendEmailRestart(emailMessage)) {
      Serial.println(emailMessage);
  }



}


void loop() {
  unsigned long currentMillis = millis();
  if (WiFi.status() != WL_CONNECTED)
      ConectareWifi(192, 168, 0, 121);
  else
      AsyncElegantOTA.loop(); // Executie Procesor OTA
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    sensors.requestTemperatures();
    // Temperature in Celsius degrees 
    float temperature = sensors.getTempCByIndex(0);
//    if (!ERR_BME) {
//        ThingSpeak.writeField(CHANNEL_ID, 1, temperature, CHANNEL_API_KEY);
    float umid = 0.5;
        delay(5000);
//        ThingSpeak.writeField(CHANNEL_ID, 2, umid, CHANNEL_API_KEY);

        ThingSpeak.setField(1,temperature);
        ThingSpeak.setField(2,umid);
        ThingSpeak.writeFields(CHANNEL_ID, CHANNEL_API_KEY);
        
        
        
        //        umid = bme.readHumidity();
//        ThingSpeak.writeField(CHANNEL_ID, 2, umid, CHANNEL_API_KEY);
//        ThingSpeak.writeFields(CHANNEL_ID, CHANNEL_API_KEY);
//        Serial.print("Umiditatea este: ");
//        Serial.println(umid);
//    }

    Serial.print(temperature);
    Serial.println(" *C");
    
    // Temperature in Fahrenheit degrees
    /*float temperature = sensors.getTempFByIndex(0);
    SerialMon.print(temperature);
    SerialMon.println(" *F");*/

    lastTemperature = String(temperature);
    
    // Check if temperature is above threshold and if it needs to send the Email alert
    if(temperature > inputMessage3.toFloat() && inputMessage2 == "true" && !emailSent){
      String emailMessage = String("Temperatura a depasit pragul. Temperatura curenta: ") + 
                            String(temperature) + String("C");
      if(sendEmailNotification(emailMessage)) {
        Serial.println(emailMessage);
        emailSent = true;
      }
      else {
        Serial.println("Email failed to send");
      }    
    }
    // Check if temperature is below threshold and if it needs to send the Email alert
    else if((temperature < inputMessage3.toFloat()) && inputMessage2 == "true" && emailSent) {
      String emailMessage = String("Temperatura a scazut sub prag. Temperatura curenta: ") + 
                            String(temperature) + String(" C");
      if(sendEmailNotification(emailMessage)) {
        Serial.println(emailMessage);
        emailSent = false;
      }
      else {
        Serial.println("Email-ul nu a fost transmis");
      }
    }
  }
}

bool sendEmailNotification(String emailMessage){
  // Set the SMTP Server Email host, port, account and password
  smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);

  // For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be 
  // enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
  //smtpData.setSTARTTLS(true);

  // Set the sender name and Email
  smtpData.setSender("PENTAGON", emailSenderAccount);

  // Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
  smtpData.setPriority("High");

  // Set the subject
  smtpData.setSubject(emailSubject);

  // Set the message with HTML format
  smtpData.setMessage(emailMessage, true);

  // Add recipients
  smtpData.addRecipient(inputMessage);

  smtpData.setSendCallback(sendCallback);

  // Start sending Email, can be set callback function to track the status
  if (!MailClient.sendMail(smtpData)) {
    Serial.println("Eroare trimitere Email, " + MailClient.smtpErrorReason());
    return false;
  }
  // Clear all data from Email object to free memory
  smtpData.empty();
  return true;
}



bool sendEmailRestart(String emailMessage) {
    // Set the SMTP Server Email host, port, account and password
    smtpData.setLogin(smtpServer, smtpServerPort, emailSenderAccount, emailSenderPassword);

    // For library version 1.2.0 and later which STARTTLS protocol was supported,the STARTTLS will be 
    // enabled automatically when port 587 was used, or enable it manually using setSTARTTLS function.
    //smtpData.setSTARTTLS(true);

    // Set the sender name and Email
    smtpData.setSender("PENTAGON", emailSenderAccount);

    // Set Email priority or importance High, Normal, Low or 1 to 5 (1 is highest)
    smtpData.setPriority("High");

    // Set the subject
    smtpData.setSubject("Serverul de temperatura a repornit !!!");

    // Set the message with HTML format
    smtpData.setMessage(emailMessage, true);

    // Add recipients
    smtpData.addRecipient("[email protected]");

    smtpData.setSendCallback(sendCallback);

    // Start sending Email, can be set callback function to track the status
    if (!MailClient.sendMail(smtpData)) {
        Serial.println("Eroare trimitere Email, " + MailClient.smtpErrorReason());
        return false;
    }
    // Clear all data from Email object to free memory
    smtpData.empty();
    return true;
}





// Callback function to get the Email sending status
void sendCallback(SendStatus msg) {
  // Print the current status
  Serial.println(msg.info());

  // Do something when complete
  if (msg.success()) {
    Serial.println("----------------");
  }
}
GND5VSDASCLSQWRTCDS1307+