#include <LiquidCrystal_I2C.h>
#include <Stepper.h>
#include "HX711.h"

// Configuração do display LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Configuração do motor de passo
#define STEPS_PER_REV 200
Stepper motor(STEPS_PER_REV, 13, 12, 11, 10);

// Configuração do sensor HX711
HX711 balanca;

// Pinos dos botões
const int btnRed = 4;    // Botão vermelho (esquerda)
const int btnYellow = 5; // Botão amarelo (direita)
const int btnEnter = 6;  // Botão Enter

// Variáveis para controle
int currentOption = 0; // 0 = Rápido, 1 = Completo
const int totalOptions = 2;

void setup() {
  // Configuração inicial do LCD
  lcd.init();
  lcd.backlight();

  // Configuração inicial dos botões
  pinMode(btnRed, INPUT_PULLUP);
  pinMode(btnYellow, INPUT_PULLUP);
  pinMode(btnEnter, INPUT_PULLUP);

  // Configuração do motor de passo
  motor.setSpeed(60); // Velocidade inicial do motor em RPM

  // Configuração da balança
  balanca.begin(A1, A0);

  // Exibe as opções iniciais no LCD
  updateLCD();
}

void loop() {
  // Navegação entre opções
  if (digitalRead(btnRed) == LOW) {
    currentOption = (currentOption - 1 + totalOptions) % totalOptions;
    updateLCD();
    delay(200);
  }

  if (digitalRead(btnYellow) == LOW) {
    currentOption = (currentOption + 1) % totalOptions;
    updateLCD();
    delay(200);
  }

  // Seleção de opção
  if (digitalRead(btnEnter) == LOW) {
    executeProgram(currentOption);
    delay(500);
  }
}

void updateLCD() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Selecione o modo:");
  lcd.setCursor(0, 1);
  lcd.print(currentOption == 0 ? "> Rapido" : "  Rapido ");
  lcd.setCursor(0, 2);
  lcd.print(currentOption == 1 ? "> Completo" : "  Completo ");
}

void executeProgram(int option) {
  int totalTime = 0;

  if (option == 0) { // Programa Rápido
    totalTime = pesagem() + injecaoAgua() + aquecimentoAgua() + preLavagem() +
                lavagem("Rapido") + escoamentoAgua() + injecaoAgua() +
                enxague() + escoamentoAgua() + centrifugacao(800);

  } else if (option == 1) { // Programa Completo
    totalTime = pesagem() + injecaoAgua() + aquecimentoAgua() +
                preLavagem() + escoamentoAgua() + injecaoAgua() +
                aquecimentoAgua() + lavagem("Completo") + escoamentoAgua() +
                injecaoAgua() + enxague() + escoamentoAgua() +
                centrifugacao(800) + secagem();
  }

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Tempo Total:");
  lcd.setCursor(0, 1);
  lcd.print(totalTime);
  lcd.print(" segundos");
  delay(3000); // Exibe o tempo total antes de retornar à seleção
  updateLCD();
}

int pesagem() {
  const float LIMITE_PESO = 5.0; // Limite máximo em kg
  const int CALIBRACAO = 2000;   // Fator de calibração, ajustar conforme necessário
  float peso = 0.0;              // Variável para armazenar o peso medido

  // Configuração do display
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Pesagem");

  // Rotação do motor
  motor.setSpeed(30);
  motor.step(STEPS_PER_REV * 2);  // 2 voltas para a direita
  motor.step(-STEPS_PER_REV * 2); // 2 voltas para a esquerda

  // Configurar o módulo HX711
  balanca.begin(A1, A0);
  balanca.set_scale(CALIBRACAO);
  balanca.tare(); // Zerar a balança

  // Realizar a leitura do peso
  peso = balanca.get_units(10); // Média de 10 leituras para maior precisão
  Serial.println(peso);
  lcd.setCursor(0, 1);
  lcd.print("Peso: ");
  lcd.print(peso);
  lcd.print(" kg");

  delay(1000);

  // Verificar se o peso excede o limite
  if (peso > LIMITE_PESO) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Peso excedido!");
    delay(5000); // Exibir mensagem por 5 segundos
    return -1;   // Retornar código de erro
  }

  return 8; // Tempo total da função em segundos
}

int injecaoAgua() {
  //8 segundos
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Injecao Agua");

  motor.setSpeed(15);
  motor.step(-STEPS_PER_REV * 2);

  return 8;
}

int aquecimentoAgua() {
  //5 segundos para cada 10 graus
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Aquec. Agua");

//AQUECIMENTO 
  delay(1000);

  return 1;
}

int preLavagem() {
  // Tempo total de pré-lavagem (20 segundos)
  const unsigned long TEMPO_TOTAL = 20000;
  const unsigned long TEMPO_ALTERNANCIA = 10000; // Alterna o sentido a cada 10 segundos
  unsigned long inicio = millis(); // Marca o tempo inicial

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Pre-Lavagem");

  // Configura a velocidade do motor
  motor.setSpeed(60);

  while (millis() - inicio < TEMPO_TOTAL) {
    unsigned long tempoDecorrido = millis() - inicio;

    if (tempoDecorrido < TEMPO_ALTERNANCIA) {
      // Primeiros 10 segundos: Sentido horário
      motor.step(STEPS_PER_REV * 2);
    } else {
      // Últimos 10 segundos: Sentido anti-horário
      motor.step(-STEPS_PER_REV * 2);
    }
  }

  return 20; // Retorna o tempo total de operação
}

int escoamentoAgua() {
  //8 segundos
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Escoar Agua");

  delay(8000);

  return 8;
}

int lavagem(String modo) {
  unsigned long TEMPO_TOTAL;
  unsigned long TEMPO_ALTERNANCIA;
  int velocidade;

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Lavagem: ");
  lcd.print(modo);

  // Configurações para os modos
  if (modo == "Rapido") {
    TEMPO_TOTAL = 30000;         // 30 segundos
    TEMPO_ALTERNANCIA = 10000;  // Alterna a cada 10 segundos
    velocidade = 60;            // 60 RPM
  } else if (modo == "Completo") {
    TEMPO_TOTAL = 60000;         // 60 segundos
    TEMPO_ALTERNANCIA = 15000;  // Alterna a cada 15 segundos
    velocidade = 100;           // 100 RPM
  } 

  // Configura a velocidade do motor
  motor.setSpeed(velocidade);

  // Marca o tempo inicial
  unsigned long inicio = millis();

  while (millis() - inicio < TEMPO_TOTAL) {
    unsigned long tempoDecorrido = millis() - inicio;

    if ((tempoDecorrido / TEMPO_ALTERNANCIA) % 2 == 0) {
      // Primeira metade do intervalo: Sentido horário
      motor.step(STEPS_PER_REV * 2);
    } else {
      // Segunda metade do intervalo: Sentido anti-horário
      motor.step(-STEPS_PER_REV * 2);
    }
  }

  return TEMPO_TOTAL / 1000; // Retorna o tempo total de operação em segundos
}

int enxague() {
  // Tempo total enxague (20 segundos)
  const unsigned long TEMPO_TOTAL = 20000;
  const unsigned long TEMPO_ALTERNANCIA = 10000; // Alterna o sentido a cada 10 segundos
  unsigned long inicio = millis(); // Marca o tempo inicial

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Pre-Lavagem");

  // Configura a velocidade do motor
  motor.setSpeed(60);

  while (millis() - inicio < TEMPO_TOTAL) {
    unsigned long tempoDecorrido = millis() - inicio;

    if (tempoDecorrido < TEMPO_ALTERNANCIA) {
      // Primeiros 10 segundos: Sentido horário
      motor.step(STEPS_PER_REV * 2);
    } else {
      // Últimos 10 segundos: Sentido anti-horário
      motor.step(-STEPS_PER_REV * 2);
    }
  }

  return 20; // Retorna o tempo total de operação
}

int centrifugacao(int rpm) {
  // Configurações
  const unsigned long TEMPO_TOTAL = 30000; // 30 segundos
  unsigned long inicio = millis();         // Marca o tempo inicial

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Centrifugacao");

  // Configura a velocidade do motor
  motor.setSpeed(rpm);

  // Executa a centrifugação pelo tempo total
  while (millis() - inicio < TEMPO_TOTAL) {
    motor.step(STEPS_PER_REV * 2); // Faz o motor rodar continuamente
  }

  return TEMPO_TOTAL / 1000; // Retorna o tempo total em segundos
}

int secagem() {
  //usuario seleciona segundos
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Secagem");

  //selecionado pelo usuário
  //motor gira apenas para a direita na velocidade de 60RPM
  //deve ter realizado a centrifugação e escoamento da água antes

  motor.setSpeed(60);

  delay(1000);

  return 5;
}