#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <time.h>
#include "WiFiClientSecure.h"

const static char *ca_cert =
"-----BEGIN CERTIFICATE-----\n" \
"MIIDdTCCAl2gAwIBAgIEH8ZmyTANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJJ\n" \
"UjELMAkGA1UECBMCRkExDzANBgNVBAcTBlNoaXJhejEUMBIGA1UEChMLVGFobGls\n" \
"Z2FyYW4xCzAJBgNVBAsTAkNBMRswGQYDVQQDExJtcXR0LnNhc2hpcmF6LmluZm8w\n" \
"HhcNMjEwOTExMDMxNTU5WhcNNDkwMTI2MDMxNTU5WjBrMQswCQYDVQQGEwJJUjEL\n" \
"MAkGA1UECBMCRkExDzANBgNVBAcTBlNoaXJhejEUMBIGA1UEChMLVGFobGlsZ2Fy\n" \
"YW4xCzAJBgNVBAsTAkNBMRswGQYDVQQDExJtcXR0LnNhc2hpcmF6LmluZm8wggEi\n" \
"MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCknRGbMJ2JXd23L5nUvm3GQAGT\n" \
"unuMW4ovtelUHHHr7AhpJguFAtf6N7biqOMaX5xeDHMljTbkh/5jjacvlbpY73Zb\n" \
"GhzEH3gMfnIkf21+GaDsX633RIP0KhQ4dw70FCYjAu+pxZ4JdfhhJvNQaTX8z3j3\n" \
"uggtPcMD2CfnWLvlpLoLYfmROnrj+L00Kp0LN9BKshqRTCCuCdfPWQp9SjviFqqa\n" \
"v5cQL6my2mb+/+Rs7IvO0H1mouDIBdTlmR4Zve9jdsx7y2ptIFAO9h7hFAvH/1q0\n" \
"ZK8un8OIk7AILwzKauYZYbMLGojrryuTMRXeat36/SPFJgeup6q1axy0BNUvAgMB\n" \
"AAGjITAfMB0GA1UdDgQWBBQm3Tz13cTp/8OHR/xcMyOThIyywDANBgkqhkiG9w0B\n" \
"AQsFAAOCAQEAOVXKpYvN0ZfyVytvOfo2pVF5X2P1apBeCAGdlGyp2HKnTvvUDvts\n" \
"Q718pM+mOk5AH2+cmgLWg8yoBSvToCRoxBlQr7dKcjy1KX2jzksWWuObDEcdTOtq\n" \
"64hwphdnmTjPyq7pDy9G+3TstvH85i5oe0lzP6LV1rG4Vt9YC8Xf6TTf6/5+z71b\n" \
"gFFRDluQkrA3lRMmfiU4hWjdgTDX3Ko2mX3PGQJLNBMcBDL7ZqchXbB5DL4gLByO\n" \
"Xk5XI957PaKjJB4SjzB/a5GRlEt3lFlzGxezS/fZlGPZJZ+UDqYqzJLka0VM6mAu\n" \
"5/Hdiit9UvQVdyyMcgfT4UM6OVNt6NIyow==\n" \
"-----END CERTIFICATE-----\n";

static StaticJsonDocument<128> jsonPubDoc;

unsigned long lastMsg = 0;
// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// ThingsBoard credentials
//const char* mqtt_server = "demo.thingsboard.io"; // e.g., "demo.thingsboard.io" for the demo instance
const char* mqtt_server = "mqtt.sashiraz.info";
const int mqtt_port = 1883; // Default MQTT port
//const char* token = "weqZxVvFU0haKKW52RVo"; // Device access token from ThingsBoard
const char* token = "CyL749W5xrq7YnQs8lHn";
// DHT sensor settings
#define DHTPIN 12     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22   // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 0;
const int   daylightOffset_sec = 0;

WiFiClientSecure espClient;
PubSubClient client(espClient);

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  String message;
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.println(message);

  DynamicJsonDocument doc(1024);
  deserializeJson(doc, message);
  String method = doc["method"];

  if (method == "setTemperature") {
    float temperature = doc["params"]["temperature"];
    Serial.print("Received Temperature: ");
    Serial.println(temperature);
    // Add your code here to handle the received temperature value
  }
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

static void publishToCloud(void)
{
  static uint32_t cntr;
  char pubBuff[128];
  Serial.println("Publish Now");
  jsonPubDoc["TestCntr"] = cntr++;
  serializeJson(jsonPubDoc, pubBuff);
  client.publish("v1/devices/me/telemetry", (const uint8_t*)pubBuff, 1, false);
  Serial.println("Publish succeeded");
  String topic = "v1/devices/me/telemetry";
  String message = String(topic) + pubBuff;
  Serial.println(message);
  
}

void publishToThingsBoard() {
  String payload = "{";
  payload += "\"temperature\": 29.0";  // Example telemetry data
  payload += "}";

  Serial.print("Publishing payload: ");
  Serial.println(payload);

  if (client.publish("v1/devices/me/telemetry", (char*) payload.c_str())) {
    Serial.println("Publish succeeded");
  } else {
    Serial.println("Publish failed");
  }
}

static void serverConnect(void)
{
  /* Loop until reconnected */
  while (!client.connected())
  {
    Serial.print("MQTT connecting ...");
    /* connect now */
    if (client.connect("ESP32Client", token, NULL))
    {
      Serial.println("Connected.");
      //digitalWrite(WiFi_LED, HIGH);
    }
    else
    {
      Serial.print("failed, status code = ");
      int state = client.state();
      Serial.println(state);
      Serial.println("Try again in 5 seconds");
      /* Wait 5 seconds before retrying */
      delay(5000);
    }
  }
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client", token, NULL)) {
      Serial.println("connected");
      client.subscribe("v1/devices/me/rpc/request/+");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

unsigned long getTime() {
  time_t now;
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    Serial.println("Failed to obtain time");
    return 0;
  }
  time(&now);
  return now;
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  //client.setServer(mqtt_server, mqtt_port);
  //client.setCallback(callback);

  /* set SSL/TLS certificate */
  espClient.setCACert(ca_cert);

  /* configure the MQTT server with IP address and port */
  client.setServer(mqtt_server, 8883);
}

void loop() {
  if (!client.connected()) {
    //reconnect();
    serverConnect();
  }
  //client.loop();
  unsigned long now = millis();
 

  if ((now - lastMsg) > 10000)
   {
     Serial.println("Keep Connection Alive ");
     publishToThingsBoard();
     lastMsg = millis();
   }
    //unsigned long timestamp = getTime() * 1000; // Convert to milliseconds
    // Prepare JSON payload
    //String payload = "{\"ts\":" + String(timestamp) + ", \"values\":{\"temperature\":" + String(temperature) + "}}";
    //String payload = "{\"temperature\": 23.0}";  // Example telemetry data
    // Publish to ThingsBoard
    //client.publish("v1/devices/me/telemetry", payload.c_str());
    //Serial.print("Published: ");
    //Serial.println(payload);
  
}