#include <Wire.h> 
#include <EEPROM.h>
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);

#define BUZZER 6
const int RECORD_ADDR = 0; // EEPROM address for best time

void setup() {
  Serial.begin(9600); // Initialize Serial Monitor
  
  pinMode(BUZZER, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, INPUT_PULLUP);

  lcd.begin();
  lcd.backlight();
  
  // Check if EEPROM has a valid record
  unsigned long bestRecord;
  EEPROM.get(RECORD_ADDR, bestRecord);
  // If EEPROM is new/empty, it will be a huge number. Reset it.
  if (bestRecord > 20000) {
    bestRecord = 9999;
    EEPROM.put(RECORD_ADDR, bestRecord);
  }

  Serial.println("--- System Online ---");
  Serial.print("Current Record: ");
  Serial.print(bestRecord);
  Serial.println(" ms");

  lcd.setCursor(0, 0);
  lcd.print("Press to start");
  while (digitalRead(5) == HIGH) { }
  delay(200); // Debounce
}

void loop() {
  unsigned long start;
  unsigned long end;
  unsigned long bestTime;

  lcd.clear();
  lcd.print("READY...");
  
  // LED Countdown
  for(int i=2; i < 5; i++) {     
    if (i > 2) digitalWrite(i - 1, LOW);
    digitalWrite(i, HIGH);
    tone(BUZZER, 245, 200);
    delay(1000);
  }

  // Random wait to prevent cheating
  delay(random(1000, 4000));

  // GO signal
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH);
  tone(BUZZER, 500, 300);
  
  start = millis();
  while(digitalRead(5) == HIGH) { } // Wait for button press
  end = millis();

  unsigned long reactionTime = end - start;

  // EEPROM Logic: Check for new record
  EEPROM.get(RECORD_ADDR, bestTime);
  
  lcd.clear();
  if (reactionTime < bestTime) {
    EEPROM.put(RECORD_ADDR, reactionTime);
    lcd.print("NEW RECORD!");
    Serial.print("NEW RECORD: ");
    bestTime = reactionTime;
  } else {
    lcd.print("Your time:");
  }

  // Display results
  lcd.setCursor(0, 1);
  lcd.print(reactionTime);
  lcd.print("ms (Best:");
  lcd.print(bestTime);
  lcd.print(")");

  // Send to Serial Monitor
  Serial.print("Last: ");
  Serial.print(reactionTime);
  Serial.print("ms | Best: ");
  Serial.print(bestTime);
  Serial.println("ms");

  delay(3000); // Show results for 3 seconds
  
  // Reset for next game
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);  
  lcd.clear();
  lcd.print("Press to start");
  while (digitalRead(5) == HIGH) { }
  delay(200);
}