#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

const char* ssid = "Wokwi-GUEST";
const char* password = "";

#define BOT_TOKEN "7700402535:AAGbVe_FSFZWzpRrtPKuKGtWP3wZSeeslJc"
const unsigned long BOT_MTBS = 1000;
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
unsigned long bot_lasttime;
bool Start = false;


#define NOTE_E5     659
#define buzzerPin   10
int statBuzzer;

#define I2C_ADDR    0x27
#define LCD_COLUMNS 16
#define LCD_LINES   2
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};
uint8_t colPins[COLS] = { 3, 2, 1, 0 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 7, 6, 5, 4 }; // Pins connected to R1, R2, R3, R4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

char sandi[6];
int index_sandi   = 0;
char sandi_check[]= "123456";
int status        = 0;
int index_lcd     = 5;

int led_merah = 11;
int led_hijau = 12;
int statLed;

int menu;

void handleNewMessages(int numNewMessages)
{
  Serial.println("handleNewMessages");
  Serial.println(String(numNewMessages));

  for (int i = 0; i < numNewMessages; i++)
  {
    String chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;

    String from_name = bot.messages[i].from_name;
    if (from_name == "")
      from_name = "Guest";

    if (text == "/start")
    {
      String welcome = "Selamat Datang Di Sistem Keamanan Pintu Rumah, " + from_name + ".\n";
      welcome += "Berikut Prompt yang dapat digunakan :\n\n";
      
      welcome += "/buzzer : Untuk Mengatur Buzzer\n";
      welcome += "/sistem : Untuk Mengatur Sistem\n";
      welcome += "/buka   : Untuk Membuka pintu\n";
      bot.sendMessage(chat_id, welcome);
    }

    if (text == "/buzzer")
    {
      String welcome = "Setting Buzzer, " + from_name + ".\n";
      welcome += "Berikut Prompt yang dapat digunakan :\n\n";
      
      welcome += "/buzzerOn  : Untuk Menyalakan Buzzer\n";
      welcome += "/buzzerOff : Untuk Mematikan  Buzzer\n";
      bot.sendMessage(chat_id, welcome);
    }
    if (text == "/buzzerOn")
    {
      String welcome = "Buzzer Dihidupkan, " + from_name + ".\n";
      bot.sendMessage(chat_id, welcome);
      statBuzzer = 0;
      buzzerOpening();
    }
    if (text == "/buzzerOff")
    {
      String welcome = "Buzzer Dimatikan, " + from_name + ".\n";
      bot.sendMessage(chat_id, welcome);
      statBuzzer = 1;
      buzzerOpening();
    }

    if (text == "/sistem")
    {
      String welcome = "Setting sistem, " + from_name + ".\n";
      welcome += "Berikut Prompt yang dapat digunakan :\n\n";
      
      welcome += "/sistemOn  : Untuk Menyalakan Sistem\n";
      welcome += "/sistemOff : Untuk Mematikan  Sistem\n";
      bot.sendMessage(chat_id, welcome);
    }
    if (text == "/sistemOn")
    {
      String welcome = "Sistem Dihidupkan, " + from_name + ".\n";
      bot.sendMessage(chat_id, welcome);
      statLed = 0;
      buzzerOpening();
    }
    if (text == "/sistemOff")
    {
      String welcome = "Sistem Dimatikan, " + from_name + ".\n";
      bot.sendMessage(chat_id, welcome);
      statLed = 1;
      buzzerOpening();
    }
    if (text == "/buka")
    {
      String welcome = "Pintu Dibuka, " + from_name + ".\n";
      statLed = 1;
      ledStatus();
      buzzerOpening();
      bot.sendMessage(chat_id, welcome);
      delay(1000);
      welcome = "Pintu Dikunci, " + from_name + ".\n";
      statLed = 0;
      ledStatus();
      buzzerOpening();
      bot.sendMessage(chat_id, welcome);
    }
  }
}

void setup() 
{
  Wire.begin(8, 9);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  secured_client.setCACert(TELEGRAM_CERTIFICATE_ROOT);

  pinMode(led_merah, OUTPUT);
  pinMode(led_hijau, OUTPUT);

  ledStatus();
  buzzerOpening();

  lcd.init();
  lcd.backlight();
  lcd.setCursor(5, 0);
  lcd.print("SYSTEM");
  lcd.setCursor(4, 1);
  lcd.print("*Secure*");
  delay(500);
  lcd.clear();
}

void loop() 
{
  ledStatus();
  lcd.setCursor(0, 0);
  lcd.print("    *Secure*");

  if (millis() - bot_lasttime > BOT_MTBS)
  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages)
    {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }

    bot_lasttime = millis();
  }

  params();
  sections();
  standby();
 
}

// --------- Buzzer Driver  ---------
void buzzerOpening(){
  tone(buzzerPin, NOTE_E5, 100);
  delay(100);  
  noTone(buzzerPin); 
  delay(100);  
  tone(buzzerPin, NOTE_E5, 100);
  delay(100); 
  noTone(buzzerPin); 
}

void buzzerAlert(){
  tone(buzzerPin, NOTE_E5, 500);
  delay(500);  
  noTone(buzzerPin); 
  delay(500);  
  tone(buzzerPin, NOTE_E5, 500);
  delay(500); 
  noTone(buzzerPin); 
  delay(500);  
  tone(buzzerPin, NOTE_E5, 500);
  delay(500); 
  noTone(buzzerPin); 
}

void buzzerButton(){
  if(statBuzzer == 0){
    tone(buzzerPin, NOTE_E5, 100);
    delay(100);    
    noTone(buzzerPin);
  }
  else{
    noTone(buzzerPin);
  }
}
// --------- -------------- ---------

// ---------   Led Driver   ---------
void ledStatus(){
  if(statLed == 0){
    digitalWrite(led_merah, 1);
    digitalWrite(led_hijau, 0);
  }
  else{
    digitalWrite(led_merah, 0);
    digitalWrite(led_hijau, 1);
  }
}
// --------- -------------- ---------

// -----------   Params   -----------
void params(){
  // ------- Password Param ---------
  char key = keypad.getKey();
  if(menu == 0 && key =='A'){
    buzzerButton();
    menu = 1;
  }
  // -------- Buzzer Param ----------
  else if(menu == 0 && key =='B'){
    buzzerButton();
    menu = 2;
  }
  // -------- Sistem Param ----------
  else if(menu == 0 && key =='C'){
    buzzerButton();
    menu = 3;
  }

  else if(menu == 0 && key == '*' || menu == 0 && key == '#' || menu == 0 && key == 'D'){
    key = NO_KEY;
  }

  else if(key == '1' ||
          key == '2' ||
          key == '3' ||
          key == '4' ||
          key == '5' ||
          key == '6' ||
          key == '7' ||
          key == '8' ||
          key == '9' ||
          key == '0' )
  {
    buzzerButton();
    sandi[0]    = key;
    menu        = 4;
  }
}
// --------- -------------- ---------

// ----------   Sections   ----------
void sections(){
  // ------- Password Section ---------
  while(menu == 1){
    char key = keypad.getKey();
    if(key == 'A' ||
       key == 'B' ||
       key == 'C' ||
       key == 'D' ||
       key == '*' ||
       key == '#'){
        key = NO_KEY;
       }
    
    lcd.setCursor(2, 0);
    lcd.print("Ganti  Sandi");

    lcd.setCursor((index_lcd + index_sandi), 1);
    if (index_sandi <= 6 && key != NO_KEY) {
      buzzerButton();
      sandi[index_sandi] = key;
      lcd.print(key);
      index_sandi = index_sandi + 1;
    }
    if (index_sandi == 6){
      for(int i = 0; i <= 6; i++){
        sandi_check[i] = sandi[i];
      }
      lcd.setCursor(1, 0);
      lcd.print("Data Tersimpan");
      for(int i = 16; i >= 0; i--){
        lcd.setCursor(i, 1);
        lcd.print("<");
        delay(50);
      }
      buzzerOpening();
      index_sandi = 0;
      lcd.clear();
      menu = 0; 
    }
  }
  // --------- -------------- ---------
  // --------- Buzzer Section ---------
  while(menu == 2){
    char key = keypad.getKey();
    lcd.setCursor(1, 0);
    lcd.print("Setting Buzzer");
    if(statBuzzer == 0){
      lcd.setCursor(13, 1);
      lcd.print(" ON");
    }
    else{
      lcd.setCursor(13, 1);
      lcd.print("OFF");
    }
    
    if(key =='*'){
      statBuzzer = 0;
      buzzerButton();
    }
    else if(key == '#'){
      statBuzzer = 1;
      buzzerButton();
    }

    if(key == 'D'){
      buzzerButton();
      lcd.setCursor(1, 0);
      lcd.print("Data Tersimpan");
      for(int i = 16; i >= 0; i--){
        lcd.setCursor(i, 1);
        lcd.print("<");
        delay(50);
      }
      buzzerOpening();
      lcd.clear();
      menu = 0;
    }
  }
  // --------- -------------- ---------

  // --------- Sistem Section ---------
  while(menu == 3){
    char key = keypad.getKey();
    lcd.setCursor(1, 0);
    lcd.print("Setting Sistem");
    if(statLed == 0){
      lcd.setCursor(13, 1);
      lcd.print(" ON");
    }
    else{
      lcd.setCursor(13, 1);
      lcd.print("OFF");
    }

    if(key =='*'){
      statLed = 0;
      buzzerButton();
    }
    else if(key == '#'){
      statLed = 1;
      buzzerButton();
    }

    if(key == 'D'){
      buzzerButton();
      lcd.setCursor(1, 0);
      lcd.print("Data Tersimpan");
      for(int i = 16; i >= 0; i--){
        lcd.setCursor(i, 1);
        lcd.print("<");
        delay(50);
      }
      buzzerOpening();
      lcd.clear();
      menu = 0;
    }
  }
  // --------- -------------- ---------
}
// --------- -------------- ---------

// ----------   Standby   -----------
void standby(){
  lcd.setCursor((index_lcd + index_sandi), 1);

  while(menu == 4){
    char key = keypad.getKey();
    if(index_sandi == 0){
      lcd.print("*");
      index_sandi = index_sandi + 1;
    }
    if (index_sandi <= 6 && key != NO_KEY) {
      buzzerButton();
      sandi[index_sandi] = key;
      lcd.print("*");
      index_sandi = index_sandi + 1;
    }

    if (index_sandi == 6){
      for(int i = 0; i <= 6; i++){
        if(sandi[i] == sandi_check[i]){
          status = status + 1;
        }
        else{
          status = status;
        }
      }
      if(status != 7){
        lcd.clear();
        lcd.setCursor(4, 0);
        lcd.print("*Secure*");
        lcd.setCursor(3, 1);
        lcd.print("Gagal Auth");
        delay(1000);
        status = 0;
        buzzerAlert();
        lcd.clear();
      }
      if(status == 7){
        lcd.clear();
        lcd.setCursor(4, 0);
        lcd.print("*Secure*");
        lcd.setCursor(4, 1);
        lcd.print("Berhasil");
        delay(1000);
        status = 0;
        statLed= 1;
        ledStatus();
        delay(1000);
        statLed= 0;
        ledStatus();
        for(int i = 16; i >= 0; i--){
          lcd.setCursor(i, 1);
          lcd.print("<");
          delay(100);
        }
        buzzerOpening();
      }
      
      lcd.clear();
      index_sandi = 0;
      menu = 0;
    }
  }
}
// --------- -------------- ---------
Sistem Off
Sistem On
Prev / On ---------------->
<----------------------------- Next / Off
<----------------- Save
<----------------- Setting Password
<----------------- Setting Buzzer
<----------------- Setting Sistem
Default : 123456