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

// Keypad and password
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
    {'1', '2', '3', 'A'},
    {'4', '5', '6', 'B'},
    {'7', '8', '9', 'C'},
    {'*', '0', '#', 'D'}
};
char passwordAllowed[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
byte rowPins[ROWS] = {3, 2, 1, 0};
byte colPins[COLS] = {A3, A2, A1, A0};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
char password[5];
int currentPassLength = 0;
const int passMaxLength = 4;
char customKey;
bool passwordSet = false;

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

bool isCodeEntered = false;
bool isGateOpen = false;

enum Screen {
    MAIN,  //"wygaszacz ekranu"
    ENTER_CODE,
    CODE_CORRECT,
    CODE_INCORRECT,
    CODE_INCORRECT_BLOCKED,
    CODE_CHANGE,
    SAFE_OPENED,
    SAFE_CLOSED
};

Screen currentScreen = MAIN;

int codeAttempt = 0;

void setup() {
    Serial.begin(9600);
    lcd.begin(16, 2);
    lcdPrintUpper("Bezpieczny");
    lcdPrintBottom("Sejfik");
}

void loop() {
    customKey = customKeypad.getKey();
    switch (customKey) {
        case '#': // Set password
            if (!passwordSet)  {
                Screen currentScreen = CODE_CHANGE;
                Serial.println("Ustaw hasło");
                lcdPrintUpper("Ustaw haslo ");

                while (currentPassLength < passMaxLength) {
                    customKey = customKeypad.getKey();
                    if (isAllowed(customKey)) {
                        password[currentPassLength] = customKey;
                        currentPassLength++;
                        lcd.print("*");
                        Serial.print("*");
                    }
                }

                password[passMaxLength] = '\0';

                passwordSet = true;
                Serial.println("Ustawiono hasło ");
                lcdPrintBottom("Ustawione B) ");
                delay(2000);
                currentScreen = MAIN;
                lcdPrintUpper("Bezpieczny");
                lcdPrintBottom("Sejfik");
            } else {
                Serial.println("Hasło już ustawione");
            }
            break;

        case 'A': // Login
            if (!passwordSet && currentScreen == MAIN) {
                Serial.println("Najpierw ustaw hasło");
                lcdPrintBottom("brak hasla :o");
                delay(2000);
                lcdPrintBottom("Sejfik       ");
            } else if (currentScreen == MAIN) {
                currentScreen = ENTER_CODE;
                Serial.println("Wpisz hasło:");
                lcdPrintUpper("Wpisz haslo ");
                char enteredPassword[5];
                currentPassLength = 0;

                while (currentPassLength < passMaxLength) {
                    customKey = customKeypad.getKey();
                    if (customKey) {
                        enteredPassword[currentPassLength] = customKey;
                        currentPassLength++;
                        lcd.print("*");
                        Serial.print("*");
                    }
                }

                enteredPassword[passMaxLength] = '\0';

                if (strcmp(password, enteredPassword) == 0) {
                    Serial.println("Poprawne");
                    currentScreen = CODE_CORRECT;
                    lcdPrintBottom("Poprawne B)");
                } else {
                    currentScreen = CODE_INCORRECT;
                    Serial.println("Niepoprawne");
                    lcdPrintBottom("Niepoprawne >:( ");
                    delay(2000);
                    currentScreen = MAIN;
                    lcdPrintUpper("Bezpieczny");
                    lcdPrintBottom("Sejfik");
                }
            }
            break;
    }
}

bool isAllowed(char key) {
    for (int i = 0; i < sizeof(passwordAllowed); i++) {
        if (passwordAllowed[i] == key) {
            return true;
        }
    }
    return false;
}

void lcdPrintUpper(const char* text) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(text);
}

void lcdPrintBottom(const char* text) {
    lcd.setCursor(0, 1);
    lcd.print(text);
}