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

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int buzzerPin = 13;

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] = {19, 18, 5, 17};
byte colPins[COLS] = {16, 4, 2, 15};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

enum Mode {
  MODE_IDLE, MODE_WAIT_ACTION, MODE_SET_ID, MODE_SET_INTERVAL, MODE_DELETE, MODE_RUNNING
};
Mode mode = MODE_IDLE;
bool systemRunning = false;
bool allowInput = false;

struct Alarm {
  int interval;
  unsigned long lastTrigger;
  bool active;
  bool snoozing;
  unsigned long snoozeStart;
};
const int MAX_ALARMS = 100;
Alarm alarms[MAX_ALARMS];
int currentID = -1;
String tempInput = "";

unsigned long snoozeTime = 5000;
unsigned long alertDuration = 3000;
bool alertActive = false;
int currentAlertID = -1;
unsigned long alertStart = 0;

int displayIndex = 0;
bool showingList = false;
unsigned long listShowTime = 0;
const unsigned long listTimeout = 4000; // زمان نمایش هر آلارم (۴ ثانیه)

void displayNextAlarm();  // <- اعلام تابع

void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(buzzerPin, OUTPUT);
  lcd.setCursor(0, 0);
  lcd.print("Press * to Start");
}

void loop() {
  char key = keypad.getKey();
if (key) {
  // اگه لیست در حال نمایشه، فقط کلیدهای * و # مجاز باشند
  if (showingList) {
    if (key == '*') {
      displayNextAlarm();
    } else if (key == '#') {
  showingList = false;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("A:Add  D:Delete");
  lcd.setCursor(0, 1);
  lcd.print("0000:Show Alarms");
}
    return;
  }
  handleKey(key);
}

  if (systemRunning && !alertActive) {
    for (int i = 0; i < MAX_ALARMS; i++) {
      if (alarms[i].active && !alarms[i].snoozing) {
        if (millis() - alarms[i].lastTrigger >= alarms[i].interval) {
          alertActive = true;
          currentAlertID = i;
          alertStart = millis();
          tone(buzzerPin, 1000);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Alarm ID:");
          lcd.print(i);
          break;
        }
      }
    }
  }

  if (alertActive && millis() - alertStart >= alertDuration) {
    noTone(buzzerPin);
    alertActive = false;
    if (currentAlertID != -1) {
      alarms[currentAlertID].snoozing = true;
      alarms[currentAlertID].snoozeStart = millis();
      currentAlertID = -1;
    }
  }

  for (int i = 0; i < MAX_ALARMS; i++) {
    if (alarms[i].snoozing && millis() - alarms[i].snoozeStart >= snoozeTime) {
      alarms[i].snoozing = false;
    }
  }
}

void handleKey(char key) {
  if (key != '*' && (
  (systemRunning && !allowInput && key != 'B' && key != 'C') ||
  (!systemRunning && !allowInput)
)) return;

  if (key == '*') {
    if (allowInput && tempInput == "0000") {
      tempInput = "";
      showingList = true;
      displayIndex = 0;
      displayNextAlarm();
      return;
    }
    if (!allowInput) {
  allowInput = true;
  systemRunning = false;
  mode = MODE_WAIT_ACTION;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("A:Add  D:Delete");
  lcd.setCursor(0, 1);
  lcd.print("0000:Show Alarms");
  return;
}
    else if (allowInput) {
      if (mode == MODE_SET_ID && tempInput != "") {
  currentID = tempInput.toInt();
  tempInput = "";
  if (currentID < 0 || currentID >= MAX_ALARMS) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Invalid ID!");
    lcd.setCursor(0, 1);
    lcd.print("Max ID: ");
    lcd.print(MAX_ALARMS - 1);
    delay(2000);
    lcd.clear();
    lcd.print("Add ID:");
    return;
  }
  mode = MODE_SET_INTERVAL;
  lcd.clear();
  lcd.print("Time (sec):");
  return;
}
      else if (mode == MODE_SET_INTERVAL && currentID >= 0 && tempInput != "") {
        int interval = tempInput.toInt();
        if (interval > 0 && currentID < MAX_ALARMS) {
          alarms[currentID].interval = interval * 1000;
          alarms[currentID].active = true;
          alarms[currentID].snoozing = false;
        }
        tempInput = "";
        mode = MODE_WAIT_ACTION;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Alarm Saved!");
        lcd.setCursor(0, 1);
        lcd.print("0000:Show Alarms");
        return;
      } else if (mode == MODE_DELETE && tempInput != "") {
        int idToDelete = tempInput.toInt();
        if (idToDelete >= 0 && idToDelete < MAX_ALARMS) {
          alarms[idToDelete].active = false;
          alarms[idToDelete].snoozing = false;
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Deleted ID: ");
          lcd.print(idToDelete);
          lcd.setCursor(0, 1);
          lcd.print("0000:Show Alarms");
        }
        tempInput = "";
        mode = MODE_WAIT_ACTION;
        return;
      }
    }
  }

  if (mode == MODE_WAIT_ACTION && key != 'A' && key != 'D' && key != '#' && key != '0') return;
  if ((mode == MODE_SET_ID || mode == MODE_SET_INTERVAL || mode == MODE_DELETE) &&
      !(isDigit(key) || key == '*')) return;
  if (key == '#') {
    systemRunning = true;
    allowInput = false;
    mode = MODE_RUNNING;
    lcd.clear();
    lcd.print("System Running");
    unsigned long now = millis();
    for (int i = 0; i < MAX_ALARMS; i++) {
      if (alarms[i].active && alarms[i].lastTrigger == 0) {
        alarms[i].lastTrigger = now;
      }
    }
    return;
  }

  if (key == 'A' && mode == MODE_WAIT_ACTION) {
    mode = MODE_SET_ID;
    tempInput = "";
    lcd.clear();
    lcd.print("Add ID:");
    return;
  }

  if (key == 'D' && mode == MODE_WAIT_ACTION) {
    mode = MODE_DELETE;
    tempInput = "";
    lcd.clear();
    lcd.print("Del ID:");
    return;
  }

  if (key == 'B') {
    if (alertActive && currentAlertID != -1) {
      noTone(buzzerPin);
      alertActive = false;
      alarms[currentAlertID].snoozing = true;
      alarms[currentAlertID].snoozeStart = millis();
      currentAlertID = -1;
    }
    return;
  }

  if (key == 'C') {
    if (alertActive && currentAlertID != -1) {
      noTone(buzzerPin);
      alertActive = false;
      alarms[currentAlertID].lastTrigger = millis();
      alarms[currentAlertID].snoozing = false;
      currentAlertID = -1;
    }
    return;
  }

  if (isDigit(key) && (
  mode == MODE_SET_ID || mode == MODE_SET_INTERVAL || mode == MODE_DELETE || mode == MODE_WAIT_ACTION
)) {
  if (tempInput == "") {
    lcd.clear();  // فقط یک بار در اولین ورودی، صفحه پاک میشه
  }
  tempInput += key;
  lcd.setCursor(0, 1);
  lcd.print(tempInput);
}
  if (showingList && key == '*') {
    displayNextAlarm();
    return;
  }
  }

 void displayNextAlarm() {
  bool found = false;
  for (int i = displayIndex; i < MAX_ALARMS; i++) {
    if (alarms[i].active) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("ID: ");
      lcd.print(i);
      lcd.setCursor(0, 1);
      lcd.print("Time: ");
      lcd.print(alarms[i].interval / 1000);
      lcd.print(" sec");
      displayIndex = i + 1;
      listShowTime = millis();
      found = true;
      break;
    }
  }

  if (!found) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("End of List");
  lcd.setCursor(0, 1);
  lcd.print("Press # to exit");
  showingList = true; // هنوز در حالت لیست هستیم تا کاربر # بزنه
  displayIndex = 0;
}
}