#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Wire.h>
#include "Adafruit_AHTX0.h"

// WiFi Credentials
const char* ssid = "HickmanWiFi";
const char* password = "BlackBriar8787@@";

// Sensor and Server Instances
Adafruit_AHTX0 aht;
AsyncWebServer server(80);

// Pins for Relays
#define FAN_RELAY_PIN 26
#define HEATER_RELAY_PIN 25  // GPIO 25 for heater relay

// Dryer State Variables
bool dryerOn = false;
bool fanRelayState = false;
bool heaterRelayState = false;
float currentTemperature = 0.0;
float currentHumidity = 0.0;
float targetTemperature = 0.0;
int dryingTime = 0;           // Total drying time in minutes
int remainingTime = 0;        // Remaining drying time in minutes
unsigned long startTime = 0;  // Time when the dryer was started (millis)

// Historical Data
const int maxHistory = 180;
std::vector<float> tempHistory;
std::vector<float> humidityHistory;

// Initialize Relays and Sensor
void setup() {
  Serial.begin(115200);

  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // AHT10 Sensor Setup
  if (!aht.begin()) {
    Serial.println("Failed to find AHT10 sensor");
    while (1) delay(10);
  }
  Serial.println("AHT10 Found");

  // Setup Relay Pins
  pinMode(FAN_RELAY_PIN, OUTPUT);
  pinMode(HEATER_RELAY_PIN, OUTPUT);
  digitalWrite(FAN_RELAY_PIN, LOW);
  digitalWrite(HEATER_RELAY_PIN, LOW);

  // Web Server Endpoints
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Filament Dryer Control");
  });

  server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request) {
    sensors_event_t humidity, temp;
    aht.getEvent(&humidity, &temp);

    currentTemperature = temp.temperature;
    currentHumidity = humidity.relative_humidity;

    // Update remaining drying time
    if (dryerOn) {
      unsigned long elapsedTime = (millis() - startTime) / 60000;  // Convert to minutes
      remainingTime = dryingTime > elapsedTime ? dryingTime - elapsedTime : 0;

      // Automatically turn off dryer when time is up
      if (remainingTime == 0) {
        dryerOn = false;
        heaterRelayState = false;
        fanRelayState = false;
        digitalWrite(HEATER_RELAY_PIN, LOW);
        digitalWrite(FAN_RELAY_PIN, LOW);
        Serial.println("Drying completed. Dryer turned off.");
      }
    } else {
      remainingTime = 0;
    }

    // Store historical data
    if (tempHistory.size() >= maxHistory) tempHistory.erase(tempHistory.begin());
    if (humidityHistory.size() >= maxHistory) humidityHistory.erase(humidityHistory.begin());
    tempHistory.push_back(currentTemperature);
    humidityHistory.push_back(currentHumidity);

    String response = "{";
    response += "\"dryerOn\":" + String(dryerOn ? "true" : "false") + ",";
    response += "\"fanRelayState\":" + String(fanRelayState ? "true" : "false") + ",";
    response += "\"heaterRelayState\":" + String(heaterRelayState ? "true" : "false") + ",";
    response += "\"temperature\":" + String(currentTemperature) + ",";
    response += "\"humidity\":" + String(currentHumidity) + ",";
    response += "\"targetTemperature\":" + String(targetTemperature) + ",";
    response += "\"dryingTime\":" + String(dryingTime) + ",";  // Total drying time
    response += "\"remainingTime\":" + String(remainingTime) + ",";  // Remaining time

    // Serialize temperature and humidity history
response += "\"tempHistory\":[";
for (size_t i = 0; i < tempHistory.size(); i++) {
    response += String(tempHistory[i]);
    if (i < tempHistory.size() - 1) response += ",";
}
response += "],";

response += "\"humidityHistory\":[";
for (size_t i = 0; i < humidityHistory.size(); i++) {
    response += String(humidityHistory[i]);
    if (i < humidityHistory.size() - 1) response += ",";
}
response += "]";


    response += "}";

    request->send(200, "application/json", response);
  });

  server.on("/control", HTTP_POST, [](AsyncWebServerRequest *request) {
    int params = request->params();
    for (int i = 0; i < params; i++) {
      AsyncWebParameter* p = request->getParam(i);
      if (p->name() == "dryerOn") {
        dryerOn = (p->value() == "true");
        if (dryerOn) {
          startTime = millis();
          fanRelayState = true;
        }
      } else if (p->name() == "targetTemperature") {
        targetTemperature = p->value().toFloat();
      } else if (p->name() == "dryingTime") {
        dryingTime = p->value().toInt();
      }
    }

    request->send(200, "application/json", "{\"status\":\"success\"}");
  });

  // CORS Handling
  DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
  DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
  DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "*");

  // Start Server
  server.begin();
}

// Monitor and Update
void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);
  currentTemperature = temp.temperature;
  currentHumidity = humidity.relative_humidity;

  // Safety Controls
  if (currentTemperature > 26.0) {
    fanRelayState = true;
    digitalWrite(FAN_RELAY_PIN, HIGH);  // Force fan on
    Serial.println("Safety: Fan forced ON due to high temperature.");
  }

  // Dryer Control Logic
  if (dryerOn) {
    if (currentTemperature < targetTemperature) {
      heaterRelayState = true;
      digitalWrite(HEATER_RELAY_PIN, HIGH);
    } else {
      heaterRelayState = false;
      digitalWrite(HEATER_RELAY_PIN, LOW);
    }

    // Ensure the fan is always on when the heater is active
    fanRelayState = true;
    digitalWrite(FAN_RELAY_PIN, HIGH);
  } else {
    heaterRelayState = false;
    digitalWrite(HEATER_RELAY_PIN, LOW);
    if (currentTemperature <= 26.0) {
      fanRelayState = false;
      digitalWrite(FAN_RELAY_PIN, LOW);
    }
  }

  // Manual Serial Command Handling
  handleSerialCommands();

  delay(5000);  // Update sensor readings every 5 seconds
}

// Handle Serial Commands to Control Relays
void handleSerialCommands() {
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n');
    command.trim();

    if (command == "fan on") {
      fanRelayState = true;
      digitalWrite(FAN_RELAY_PIN, HIGH);
      Serial.println("Fan relay activated.");
    } else if (command == "fan off") {
      fanRelayState = false;
      digitalWrite(FAN_RELAY_PIN, LOW);
      Serial.println("Fan relay deactivated.");
    } else if (command == "heater on") {
      heaterRelayState = true;
      digitalWrite(HEATER_RELAY_PIN, HIGH);
      fanRelayState = true;
      digitalWrite(FAN_RELAY_PIN, HIGH);
      Serial.println("Heater relay activated. Fan ON for safety.");
    } else if (command == "heater off") {
      heaterRelayState = false;
      digitalWrite(HEATER_RELAY_PIN, LOW);
      Serial.println("Heater relay deactivated.");
    } else {
      Serial.println("Unknown command. Use 'fan on', 'fan off', 'heater on', or 'heater off'.");
    }
  }
}
