#include <IRremote.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

// LCD Setup
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Pins
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;
const int buzzerPin = 7;
const int RECV_PIN = 12;
const int irLedPin = 8;
const int gateInputPin = 6;  // AND gate output pin

IRrecv irrecv(RECV_PIN);
decode_results results;

// Single password button code
unsigned long passwordCode = 0xC1AAA15E;  // Replace with your desired IR remote button code

// Attempt counter and lockout variables
int failedAttempts = 0;
const int maxAttempts = 3;
bool lockedOut = false;
unsigned long lockoutStartTime = 0;
const unsigned long lockoutDuration = 10000;  // 10 seconds lockout

void setup() {
  Serial.begin(9600);
  Serial.println("Start");

  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(irLedPin, OUTPUT);
  pinMode(gateInputPin, INPUT); // For physical AND gate

  digitalWrite(irLedPin, LOW);

  irrecv.enableIRIn();
  Serial.println("IR Testing Started");

  lcd.begin();
  lcd.setBacklight((uint8_t)1);

  // Startup Animation
  for (int i = 0; i <= 255; i += 5) {
    setColor(i, i, i);
    delay(10);
  }
  for (int i = 255; i >= 0; i -= 5) {
    setColor(i, i, i);
    delay(10);
  }

  lcd.clear();
  lcd.print("Enter Password:");

  setColor(255, 255, 255);
}

void loop() {
  // Handle lockout timing
  if (lockedOut) {
    if (millis() - lockoutStartTime >= lockoutDuration) {
      lockedOut = false;
      failedAttempts = 0;
      lcd.clear();
      lcd.print("Enter Password:");
      setColor(255, 255, 255);
      Serial.println("Lockout ended. Ready.");
    } else {
      // Still locked out, show message
      lcd.setCursor(0, 0);
      lcd.print("LOCKED OUT   ");
      lcd.setCursor(0, 1);
      lcd.print("Wait...      ");
      return;
    }
  }

  if (irrecv.decode(&results)) {
    Serial.println("IR Received: ");
    Serial.println(results.value, HEX);

    digitalWrite(irLedPin, HIGH);
    delay(400);
    digitalWrite(irLedPin, LOW);

    lcd.setCursor(0, 1);
    lcd.print("Key: ");
    lcd.print(results.value, HEX);
    lcd.print("    ");

    bool logicOverride = digitalRead(gateInputPin) == HIGH;

    if (results.value == passwordCode && logicOverride) {
      lcd.clear();
      lcd.print("Access Granted!");
      setColor(255, 0, 255);
      playSuccessTone();
      failedAttempts = 0;
    } else if (results.value == passwordCode && !logicOverride) {
      lcd.clear();
      lcd.print("Denied: Gate Low");
      lcd.setCursor(0, 1);
      lcd.print("Touch & Press Btn");
      setColor(255, 255, 0);
      playFailTone();
    } else {
      lcd.clear();
      lcd.print("Access Denied!");
      setColor(0, 255, 0);
      playFailTone();

      failedAttempts++;

      if (failedAttempts >= maxAttempts) {
        lockedOut = true;
        lockoutStartTime = millis();
        lcd.clear();
        lcd.print("LOCKED OUT");
        setColor(255, 0, 0);  // Red during lockout
        Serial.println("System locked out!");
      }
    }

    delay(3000);
    resetEntry();

    irrecv.resume();
  }
}

void setColor(int red, int green, int blue) {
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}

void playSuccessTone() {
  for (int i = 0; i < 3; i++) {
    digitalWrite(buzzerPin, HIGH);
    delay(100 + i * 50);
    digitalWrite(buzzerPin, LOW);
    delay(100);
  }
}

void playFailTone() {
  digitalWrite(buzzerPin, HIGH);
  delay(500);
  digitalWrite(buzzerPin, LOW);
  delay(200);
  digitalWrite(buzzerPin, HIGH);
  delay(200);
  digitalWrite(buzzerPin, LOW);
}

void resetEntry() {
  lcd.clear();
  lcd.print("Press Button:");
  setColor(255, 255, 255);
  Serial.println("Waiting...");
}