#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <DHT.h>
#include <Wire.h>

#define DHTPIN 2        // Pino onde o DHT22 está conectado
#define DHTTYPE DHT22   // Tipo do sensor DHT
#define RELAY1_PIN 3    // Pino para o relé 1
#define RELAY2_PIN 4    // Pino para o relé 2
#define BUTTON_PIN 5    // Pino para o botão de start/stop
#define DOOR_SWITCH_PIN 6 // Pino para o interruptor da porta
#define TEMP_THRESHOLD 65.0  // Temperatura limite em graus Celsius
#define HUMIDITY_THRESHOLD 6.0  // Umidade mínima em porcentagem
#define TIMER_DURATION 3600000 // Duração do temporizador em milissegundos (1 hora)
#define RELAY2_OFF_DELAY 10000 // Tempo para o temporizador de desligamento após desativação do relé 2 (1 minuto)
#define BUTTON_HOLD_TIME 3000  // Tempo necessário para acionar o botão (3 segundos)

#define SCREEN_WIDTH 128  // Largura do display OLED
#define SCREEN_HEIGHT 64  // Altura do display OLED
#define OLED_RESET -1     // Definir o reset como -1 se não for usado

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

DHT dht(DHTPIN, DHTTYPE);

bool systemOn = false;  // Variável para armazenar o estado do sistema
bool relay2Locked = false; // Variável para bloquear a reativação do relé 2
bool shutdownInitiated = false;  // Variável para indicar se o processo de shutdown foi iniciado
unsigned long startTime = 0;  // Tempo de início do sistema
unsigned long relay2OffStartTime = 0;  // Tempo de início do temporizador de desligamento do relé 2
unsigned long shutdownStartTime = 0;  // Tempo de início do processo de shutdown
unsigned long buttonPressTime = 0;  // Tempo de início da pressão do botão

void setup() {
  pinMode(RELAY1_PIN, OUTPUT);
  pinMode(RELAY2_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);  // Usando resistor de pull-up interno
  pinMode(DOOR_SWITCH_PIN, INPUT_PULLUP);  // Usando resistor de pull-up interno

  dht.begin();
  
  // Inicializa o display OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // Endereço I2C do OLED
    for (;;);  // Trava se não conseguir inicializar o display
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  
  // Mensagem inicial
  display.setCursor(0, 0);
  display.setTextSize(1);
  display.print("   BRASTEMP ACTIVE");
  display.setCursor(0, 20);
  display.print("   PRESSIONAR START       PARA INICIAR");
  display.display();  // Exibe as mensagens iniciais
  
  digitalWrite(RELAY1_PIN, LOW);  // Inicialmente, ambos os relés estão desligados
  digitalWrite(RELAY2_PIN, LOW);
}

void loop() {
  // Verifica se o interruptor da porta foi ativado
  if (digitalRead(DOOR_SWITCH_PIN) == LOW) {
    shutdownSystem("Door Open");
    return;
  }

  // Verifica se o botão foi pressionado
  if (digitalRead(BUTTON_PIN) == LOW) {
    if (buttonPressTime == 0) {
      buttonPressTime = millis();  // Registra o tempo de início da pressão do botão
    }
    // Verifica se o botão foi mantido pressionado por 3 segundos
    else if (millis() - buttonPressTime >= BUTTON_HOLD_TIME) {
      if (systemOn) {
        if (!shutdownInitiated) {
          // Desliga o relé 2 e inicia o temporizador de 60 segundos para desligar o sistema
          digitalWrite(RELAY2_PIN, LOW);
          relay2Locked = true;  // Bloqueia a reativação do relé 2
          shutdownInitiated = true;  // Inicia o processo de shutdown
          shutdownStartTime = millis();
          updateDisplay("Relay 2 Off", "Shutdown in 60s");
        }
      } else {
        // Inicia o sistema
        systemOn = true;
        digitalWrite(RELAY1_PIN, HIGH);
        digitalWrite(RELAY2_PIN, HIGH);
        startTime = millis();  // Registra o tempo de início
        shutdownInitiated = false;  // Reseta o estado de shutdown
        relay2Locked = false;  // Reseta o bloqueio do relé 2
        updateDisplay("System On", "");
      }
      buttonPressTime = 0;  // Reseta o tempo do botão após a ação
    }
  } else {
    buttonPressTime = 0;  // Reseta o tempo do botão se ele for liberado antes de 3 segundos
  }

  if (systemOn && !shutdownInitiated) {
    float temperature = dht.readTemperature();
    float humidity = dht.readHumidity();

    if (isnan(temperature) || isnan(humidity)) {
      updateDisplay("Sensor Error", "");
      return;
    }

    // Verifica a umidade mínima e desliga o relé 2 se for menor que o limite
    if (humidity <= HUMIDITY_THRESHOLD || millis() - startTime >= TIMER_DURATION) {
      if (!shutdownInitiated) {
        digitalWrite(RELAY2_PIN, LOW);  // Desliga o relé 2
        relay2Locked = true;  // Bloqueia a reativação do relé 2
        shutdownInitiated = true;  // Inicia o processo de shutdown
        shutdownStartTime = millis();
        updateDisplay("Relay 2 Off", "Shutdown in 60s");
      }
    }

    // Controle do relé 2 com base na temperatura
    if (temperature >= TEMP_THRESHOLD) {
      digitalWrite(RELAY2_PIN, LOW);  // Desliga o relé 2
    } else if (!relay2Locked) {
      digitalWrite(RELAY2_PIN, HIGH);  // Liga o relé 2
    }

    // Atualiza o display OLED
    updateDisplayData(temperature, humidity);
  }
  
  // Verifica se o temporizador de shutdown foi acionado e se o tempo de 60 segundos já passou
  if (shutdownInitiated) {
    unsigned long elapsedShutdownTime = millis() - shutdownStartTime;
    if (elapsedShutdownTime < RELAY2_OFF_DELAY) {
      updateShutdownDisplay((RELAY2_OFF_DELAY - elapsedShutdownTime) / 1000);  // Atualiza o display com o tempo restante
    } else {
      shutdownSystem("Shutdown Complete");
    }
  }
}

void updateDisplayData(float temperature, float humidity) {
  // Função para atualizar todas as informações no display de forma organizada
  display.clearDisplay();
  
  // Exibe temperatura
  display.setCursor(0, 0);
  display.print("T: ");
  display.print(temperature, 1);
  //display.write(0xDF);  // Símbolo de grau
  display.print(" C");

  // Exibe umidade
  display.setCursor(0, 10);
  display.print("H: ");
  display.print(humidity, 1);
  display.print(" %");

  // Exibe tempo decorrido
  display.setCursor(0, 20);
  display.print("TEMPO: ");
  unsigned long elapsedTime = (millis() - startTime) / 1000;
  display.print(elapsedTime / 60);
  display.print("m ");
  display.print(elapsedTime % 60);
  display.print("s");

  // Exibe status dos relés
  display.setCursor(0, 30);
  display.print("SISTEMA: ");
  display.print(digitalRead(RELAY1_PIN) ? "ON" : "OFF");

  display.setCursor(0, 40);
  display.print("AQUECIMENTO: ");
  display.print(digitalRead(RELAY2_PIN) ? "ON" : "OFF");

  display.display();  // Atualiza o display
}

void updateShutdownDisplay(unsigned long shutdownTimeLeft) {
  // Função para exibir o tempo restante para o shutdown
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("System Shutdown");
  display.setCursor(0, 10);
  display.print("in: ");
  display.print(shutdownTimeLeft);
  display.print("s");
  display.display();
}

void updateDisplay(String line1, String line2) {
  // Função para exibir mensagens customizadas
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print(line1);
  display.setCursor(0, 10);
  display.print(line2);
  display.display();
}

void shutdownSystem(String reason) {
  // Função para desligar o sistema completamente
  digitalWrite(RELAY1_PIN, LOW);
  digitalWrite(RELAY2_PIN, LOW);
  systemOn = false;  // Desliga o sistema
  updateDisplay(reason, "Shutdown Initiated");
}