#include "SimpleTimer.h"
#include "ArduinoJson.h"
#include <WiFi.h>
#include <PubSubClient.h>
#include <string>
#include <FastBot.h>
#include "SimpleVector.h"


#define BOT_TOKEN "6780587077:AAGfuAjlpo__OTIEb-kCSRe8dQCd1jEZPis"

#define CHAT_ID "460540516"
FastBot bot(BOT_TOKEN);

int DELAY = 1000;

const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1884;
const char* mqtt_topic = "TOIP/lab4/boiler/temperature"; // MQTT topic to subscribe and publish
const char* mqtt_username = "ro";
const char* mqtt_password = "readonly";

int relayPin = 21;

WiFiClient espClient;
PubSubClient client(espClient);

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

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password, 5);

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

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

float wanted_temperature = 27.0;
float hysteresis = 0.5;
float temperature = 0.0;

void setup() {
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW);

  Serial.begin(115200);

  bot.setChatID(CHAT_ID);

  bot.attach(messageParser);

  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

}

String arg(String str) {
  String result = "";
  bool enableWriting = false;
  for(int i = 0; i < str.length(); i++) {
    if(enableWriting && str[i] != ' ') result += str[i];
    if(str[i] == ' ') enableWriting = true;
  }
  return result;
}

void messageParser(FB_msg& msg) {
  Serial.println("Reciveed command: " + msg.text);
  if (msg.text.startsWith("/set_wanted_temperature")) {
    float new_wanted_temperature = arg(msg.text).toFloat();
    bot.sendMessage("Wanted temperature was changed from " + String(wanted_temperature) + "°C to " + String(new_wanted_temperature) + "°C");
    wanted_temperature = new_wanted_temperature;
    update_relay_state();
  } else if(msg.text.startsWith("/thermostat_settings")) {
    bot.sendMessage("Wanted temperature: " + String(wanted_temperature) + "°C, hysteresis: " + String(hysteresis) + "°C");
  }  else if (msg.text.startsWith("/help")) {
        String helpMessage = "Available Commands:\n";
        helpMessage += "/set_wanted_temperature <temp> - Set the desired temperature. Example: /set_wanted_temperature 25\n";
        helpMessage += "/thermostat_settings - View the current thermostat settings and the last known temperature.\n";
        helpMessage += "/current_temperature - Get the latest reading of the current temperature.\n";
        helpMessage += "/help - Show this help message.\n";
        helpMessage += "Use these commands to control and monitor your heating system remotely.";
        bot.sendMessage(helpMessage);
    }
}

void loop() {
  bot.tick();
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
} 

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESPClient-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
      Serial.println("connected");
      // Once connected resubscribe
      client.subscribe(mqtt_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


void callback(char* topic, byte* payload, unsigned int length) {
  char message[length];
  for (int i = 0; i < length; i++) {
    message[i] = (char)payload[i];
  }

  // Extract temperature from JSON
  temperature = strtof(message, NULL);

  update_relay_state();
}

void update_relay_state() {
  if (temperature < wanted_temperature - hysteresis) {
    digitalWrite(relayPin, HIGH); // Turn on relay
    String msg = "";
    msg += "Temperature < ";
    msg += String(wanted_temperature - hysteresis);
    msg += "°C - Relay ON";
    Serial.println(msg);
  } else if (temperature > wanted_temperature + hysteresis) {
    digitalWrite(relayPin, LOW); // Turn on relay
    String msg = "";
    msg += "Temperature > ";
    msg += (wanted_temperature + hysteresis);
    msg += "°C - Relay OFF";
    Serial.println(msg);
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module