#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <MLX90614.h>
#include <VL53L0X.h>
#include <PID_v1_bc.h>
#include "RBDdimmer.h"

#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
// VL53L0X setup
VL53L0X sensor;
// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Push button pins
#define UP_BTN 6
#define DOWN_BTN 5
#define SWITCH_BTN 4
#define START_STOP_BTN 2

// Buzzer pin
#define BUZZER_PIN 7

// AC dimmer pin
#define outputPin  3
#define zerocross  2
dimmerLamp dimmer(outputPin);

// PID variables
double Setpoint, Input, output;
PID myPID(&Input, &output, &Setpoint, 2, 5, 1, DIRECT);

// Variables
double jarakset = 50.0;
double jarakread;
double suhuSet = 35.0; // Default set temperature (in Celsius)
unsigned long timerSet = 5 * 60; // Default set time (in seconds)
unsigned long remainingTime = 0;
bool pidRunning = false;
bool countdownActive = false;
unsigned long previousMillis = 0;
const unsigned long interval = 1000; // Timer interval (1 second)
int selectedVar = 0; // 0 for suhuSet, 1 for timerSet

// Debounce variables
unsigned long lastButtonPress = 0;
const unsigned long DEBOUNCE_DELAY = 200;

void setup() {
  pinMode(UP_BTN, INPUT_PULLUP);
  pinMode(DOWN_BTN, INPUT_PULLUP);
  pinMode(SWITCH_BTN, INPUT_PULLUP);
  pinMode(START_STOP_BTN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  mlx.begin();
  sensor.init();
  lcd.init();
  lcd.backlight();
  dimmer.begin(NORMAL_MODE, ON); //dimmer initialisation: name.begin(MODE, STATE)
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 100);
}

void handleButtonPress(int pin, void (*callback)()) {
  if (digitalRead(pin) == LOW) {
    unsigned long currentMillis = millis();
    if (currentMillis - lastButtonPress >= DEBOUNCE_DELAY) {
      lastButtonPress = currentMillis;
      callback();
    }
  }
}

void switchVariable() {
  selectedVar = (selectedVar + 1) % 3;
}

void increaseValue() {
  if (selectedVar == 0) suhuSet += 1.0;
  else if (selectedVar == 1) timerSet += 60;
  else if (selectedVar == 2) jarakset += 1.0;
}

void decreaseValue() {
  if (selectedVar == 0 && suhuSet > 0) suhuSet -= 1.0;
  else if (selectedVar == 1 && timerSet >= 60) timerSet -= 60;
  else if (selectedVar == 2 && jarakset > 0) jarakset -= 1.0;
}

void toggleStartStop() {
  if (pidRunning) {
    pidRunning = false;
    countdownActive = false;
    dimmer.setPower(0); // Stop dimmer (heating)
    digitalWrite(BUZZER_PIN, LOW); // Turn off buzzer if running
  } else {
    pidRunning = true;
    countdownActive = true;
    remainingTime = timerSet; // Reset timer
    dimmer.setPower(0); // Reset power to avoid incorrect heating behavior when restarted
  }
}

void loop() {
  Input = mlx.readObjectTempC();
  jarakread = sensor.readRangeSingleMillimeters() / 10.0; // Convert mm to cm

  // Handle button presses
  handleButtonPress(SWITCH_BTN, switchVariable);
  handleButtonPress(UP_BTN, increaseValue);
  handleButtonPress(DOWN_BTN, decreaseValue);
  handleButtonPress(START_STOP_BTN, toggleStartStop);

  // PID Control and Timer Countdown
  if (pidRunning && countdownActive) {
    Setpoint = suhuSet;
    myPID.Compute();
    dimmer.setPower(output);

    if (millis() - previousMillis >= interval) {
      previousMillis = millis();
      if (remainingTime > 0) {
        remainingTime--;
      } else {
        countdownActive = false;
        pidRunning = false;
        dimmer.setPower(0);
        digitalWrite(BUZZER_PIN, HIGH);
        delay(3000); // Buzzer alert for 3 seconds
        digitalWrite(BUZZER_PIN, LOW);
      }
    }
  }

  // LCD Display
  lcd.setCursor(1, 0);
  lcd.print("J: ");
  lcd.print(jarakset);
  lcd.print("cm / ");
  lcd.print(jarakread);
  lcd.print("cm   ");

  lcd.setCursor(1, 1);
  lcd.print("S: ");
  lcd.print(suhuSet);
  lcd.print("c / ");
  lcd.print(Input);
  lcd.print("c   ");

  lcd.setCursor(1, 2);
  lcd.print("T: ");
  unsigned long displayTime = pidRunning ? remainingTime : timerSet;
  unsigned long hours = displayTime / 3600;
  unsigned long minutes = (displayTime % 3600) / 60;
  unsigned long seconds = displayTime % 60;
  if (hours < 10) lcd.print("0");
  lcd.print(hours);
  lcd.print(":");
  if (minutes < 10) lcd.print("0");
  lcd.print(minutes);
  lcd.print(":");
  if (seconds < 10) lcd.print("0");
  lcd.print(seconds);

  lcd.setCursor(0, 3);
  if (!pidRunning) {
    lcd.print("Stopped             "); // Show stopped message when PID is off
  } else {
    lcd.print("Power: ");
    lcd.print((int)output);
    lcd.print("   ON ");
  }

  if (selectedVar == 0){
    lcd.setCursor(0, 1);
    lcd.print(">");
    lcd.setCursor(0, 2);
    lcd.print(" ");
    lcd.setCursor(0, 0);
    lcd.print(" ");
  }
  if (selectedVar == 1){
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(0, 2);
    lcd.print(">");
    lcd.setCursor(0, 0);
    lcd.print(" ");
  }
   if (selectedVar == 2){
    lcd.setCursor(0, 1);
    lcd.print(" ");
    lcd.setCursor(0, 2);
    lcd.print(" ");
    lcd.setCursor(0, 0);
    lcd.print(">");
  }
}