#include <WiFiClientSecure.h>
#include <MQTTClient.h>
#include <ArduinoJson.h>
#include <DHT.h>

#include "secrets.h"

#define AWS_THING_NAME "iotesp32datafrontier"
#define AWS_IOT_PUBLISH_BUTTON "garcom/botao"
#define AWS_IOT_PUBLISH_SENSOR_TEMP "sensors/temp_pub"
#define AWS_IOT_PUBLISH_SENSORS_HUM "sensors/humid_pub"
#define AWS_IOT_PUBLISH_SENSORS_LIGHT "sensors/light_pub"

#define TABLE_NUMBER 198  // table number
#define BUTTON_PIN 23    // push-buton pin
#define DHT_PIN 15          // Pino onde o sensor DHT está conectado
#define DHT_TYPE DHT22     // Tipo do sensor DHT (DHT11 ou DHT22)

#define LIGHT_SENSOR_PIN 36 // ESP32 pin GIOP36 (ADC0)

DHT dht(DHT_PIN, DHT_TYPE);
WiFiClientSecure net = WiFiClientSecure();
MQTTClient client = MQTTClient(612);
volatile unsigned long lastCallWaiterTime = 0; // Records last call waiter time
volatile bool callWaiter = false;              // Flag to call waiter
unsigned long lastSensorTime = 0;
unsigned long int value = 0;
const unsigned long interval = 300000; // Intervalo de 5 minutos (300000 milissegundos)


void connectAWS() {
  // Configure WiFiClientSecure to use the AWS IoT device credentials
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);

  // Connect to the MQTT broker on the AWS endpoint
  client.begin(AWS_IOT_ENDPOINT, 8883, net);

  Serial.println("Connecting to AWS IOT");

  while (!client.connected()) {
    Serial.print("Connecting to AWS IoT...");
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.lastError());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}


void setup() {
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonPressed, FALLING);

  connectWiFi();
  connectAWS();
}


void buttonPressed() {
  unsigned long time = millis();
  // Evita chamar varias vezes (debounce)
  if (time - lastCallWaiterTime > 200) {
    callWaiter = true;
    lastCallWaiterTime = time;
  }
}

void loop()  {

  if (!client.connected()) {
    connectAWS();
  }
  // Sends and receives packets
  client.loop();
  unsigned long currentMillis = millis();
  if (currentMillis - lastSensorTime >= interval) {
    sendSensorData();
    lastSensorTime = currentMillis;
    Serial.println(lastSensorTime);
  }

  if (callWaiter) {
    sendBotaoGarcom();
  }
 

}

void sendBotaoGarcom () {
    value++;
    Serial.println("Chamando o garcom..." + String(value));

    // Create JSON document
    StaticJsonDocument<200> json;
    json["tableNumber"] = TABLE_NUMBER;
    json["deviceTime"] = millis();
    json["deviceName"] = AWS_THING_NAME;

    // Serialize JSON
    char jsonBuffer[128];
    serializeJson(json, jsonBuffer);

    // Publish message to callwaiter/button topic
    client.publish(AWS_IOT_PUBLISH_BUTTON, jsonBuffer);

    // Reset the callWaiter flag
    callWaiter = false;
}

void sendSensorData() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  
  int analogValue = analogRead(LIGHT_SENSOR_PIN);

  String lightLevel = getLightLevel(analogValue);
  // Exibe o nível de luz
  Serial.println(lightLevel);  
 

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Falha ao ler o sensor DHT!");
    return;
  }
  
  Serial.println("Temperatura: " + String(temperature) + "°C");
  Serial.println("Umidade: " + String(humidity) + "%");
  Serial.println("Luminosidade: " + String(lightLevel) + " lux");

  // StaticJsonDocument<200> doc;
  // doc["device_time"] = millis();
  // doc["device_name"] = AWS_THING_NAME;
  // doc["humidity"] = humidity;
  // doc["temperature"] = temperature;
  // char jsonBuffer[128];
  // serializeJson(doc, jsonBuffer); // print to client
  // client.publish(AWS_IOT_PUBLISH_SENSORS, jsonBuffer);
  sendToMQTT(AWS_IOT_PUBLISH_SENSOR_TEMP, temperature);
  sendToMQTT(AWS_IOT_PUBLISH_SENSORS_HUM, humidity);
  sendToMQTT(AWS_IOT_PUBLISH_SENSORS_LIGHT, float(analogValue));
  
}

// Função para obter o nível de luz com base no valor analógico lido
String getLightLevel(int analogValue) {
  if (analogValue < 40) {
    return "Dark";
  } else if (analogValue <= 800) {
    return "Dim";
  } else if (analogValue > 800 && analogValue <= 2000) {
    return "Light";
  } else if (analogValue > 2000 && analogValue <= 3200) {
    return "Bright";
  } else {
    return "Very bright";
  }
}

void sendToMQTT(const char* topic, float value) {
  StaticJsonDocument<200> doc;
  doc["device_time"] = millis();
  doc["device_name"] = AWS_THING_NAME;
  doc["value"] = value;
  char jsonBuffer[128];
  serializeJson(doc, jsonBuffer); // print to client
  client.publish(topic, jsonBuffer);
}