#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Keypad.h>
#include <SoftwareSerial.h>

#define SS_PIN 10
#define RST_PIN 9
#define BUZZER_PIN 7

MFRC522 rfid(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x20, 16, 2); // Ensure this address is correct for your LCD
Servo myServo;
SoftwareSerial espSerial(0, 1); // Using pins 0 and 1 is not recommended for SoftwareSerial if you are also using them for USB communication

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {A0, A1, A2, A3};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

String correctPassword = "1234";
String enteredPassword = "";

void setup() {
  pinMode(BUZZER_PIN, OUTPUT);
  SPI.begin();
  rfid.PCD_Init();
  myServo.attach(6);
  myServo.write(70); // Initial position set to 70 degrees
  Serial.begin(9600);
  espSerial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Scan RFID/Enter PW");
}

void loop() {
  if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
    lcd.clear();
    lcd.print("Card Detected");
    handleRFID();
    delay(2000);
    lcd.clear();
    lcd.print("Scan RFID/Enter PW");
  }
  handleKeypad();
  if (espSerial.available()) {
    String message = espSerial.readStringUntil('\n');
    message.trim();
    handleESP32Message(message);
  }
}

void handleRFID() {
  String cardID = "";
  for (byte i = 0; i < rfid.uid.size; i++) {
    cardID += String(rfid.uid.uidByte[i], HEX);
  }
  cardID.toUpperCase();
  if (cardID == "33FCED2F" || cardID == "3356F7" || cardID == "90ABCDEF") {
    grantAccess();
  } else {
    denyAccess();
  }
}

void handleKeypad() {
  char key = keypad.getKey();
  if (key) {
    if (key == '#') {
      if (enteredPassword == correctPassword) {
        grantAccess();
      } else {
        denyAccess();
      }
      enteredPassword = "";
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Scan RFID/Enter PW");
    } else if (key == '*') {
      enteredPassword = "";
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Scan RFID/Enter PW");
    } else {
      enteredPassword += key;
      lcd.setCursor(0, 1);
      lcd.print(enteredPassword);
    }
  }
}

void handleESP32Message(String message) {
  if (message == "GRANTED") {
    grantAccess();
  } else if (message == "DENIED") {
    denyAccess();
  }
}

void grantAccess() {
  lcd.clear();
  lcd.print("Access Granted");
  buzz(200);  // Buzz for 200 milliseconds
  myServo.write(150); // Move servo to 90 degrees
  delay(5000);        // Wait for 5 seconds
  myServo.write(90);  // Move servo back to 70 degrees
  lcd.clear();
  lcd.print("Scan RFID/Enter PW");
}

void denyAccess() {
  lcd.clear();
  lcd.print("Access Denied");
  delay(2000);
  lcd.clear();
  lcd.print("Scan RFID/Enter PW");
}

void buzz(unsigned long duration) {
  tone(BUZZER_PIN, 1000); // Play 1000 Hz tone
  delay(duration);
  noTone(BUZZER_PIN); // Stop tone
}