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

// Initialisiere die LCD-Displays mit den jeweiligen I2C-Adressen
LiquidCrystal_I2C lcd1(0x27, 16, 2);  // Adresse des ersten Displays
LiquidCrystal_I2C lcd2(0x26, 16, 2);  // Adresse des zweiten Displays

// Keypad Konfiguration
const byte ROWS = 4;  // 4 Reihen
const byte COLS = 3;  // 3 Spalten
char keys[ROWS][COLS] = {{'1', '2', '3'},
                         {'4', '5', '6'},
                         {'7', '8', '9'},
                         {'*', '0', '#'}};  // Aufbau des  Tastenfeldes
byte rowPins[ROWS] = {8, 7, 6, 5};          // Pins für die Reihen
byte colPins[COLS] = {4, 3, 2};             // Pins für die Spalten
Keypad keypad =
    Keypad(makeKeymap(keys), rowPins, colPins, ROWS,
           COLS);  // Variable Keypad einfügen und mit Informationen füllen

// Aufgaben und Antworten
struct Task {
    String question;
    float correctAnswer;
};

Task tasks[] = {
    {"Ein 2.5kg schwerer Sack Kartoffeln soll in die Höhe gehoben werden. Wie "
     "viel Kraft wird für diesen Vorgang benötigt in N?",
     24.5},
    {"Auto 30km/h, 40m entfernt. Laufgeschw.?",
     5.0 / (40.0 / (30.0 * 1000.0 / 3600.0))},
    {"Wasserkocher 1000W, 0.5L von 20C auf 100C. Zeit in s?",
     (0.5 * 80 * 210) / 1000.0}};

int currentTask = 0;      // Aktuelle Aufgabe
String userInput = "";    // Speichert die Eingabe des Nutzers
unsigned long startTime;  // Speichert die Startzeit der Aufgabe
bool isFirstTask = true;  // Flag für die erste Aufgabe

void showFinalCode() {
    lcd2.clear();
    lcd2.setCursor(0, 0);
    lcd2.print("Zahlenkombination:");
    lcd2.setCursor(0, 1);
    lcd2.print("171");
    delay(5000);
    lcd2.clear();
    lcd1.clear();
    lcd1.setCursor(0, 0);
    lcd1.print("Spiel startet");
    lcd1.setCursor(0, 1);
    lcd1.print("neu");
    delay(5000);
    currentTask = 0;
    isFirstTask = true;
    userInput = "";
}  // wenn Spiel abgeschlossen ist, wird das Display einmal gereinigt und der
   // Endcode angezeigt sowie ein Hinweis ausgegeben dass ein Neues spiel
   // gestartet wird

void showNextTaskHint(int taskIndex) {
    int numberToShow = 0;

    if (taskIndex == 0) {
        numberToShow = 1;
    } else if (taskIndex == 1) {
        numberToShow = 7;
    } else if (taskIndex == 2) {
        numberToShow = 1;
    }  // Damit nach der jeweiligen Aufgabe die korrekte Nummer dargestellt wird

    lcd1.clear();
    lcd1.setCursor(0, 0);
    lcd1.print("Deine Nummer ist ");
    lcd1.setCursor(0, 1);
    lcd1.print(numberToShow);
    delay(2000);
    lcd1.clear();
    // Darstellung der neu freigeschalteten Nummer

    if (taskIndex < 2) {
        lcd2.setCursor(0, 0);
        lcd2.print("Weiter zur ");
        lcd2.setCursor(0, 1);
        lcd2.print("naechsten Aufgabe...");
        delay(2000);
        lcd2.clear();
        currentTask++;  // Hochzählen der aktuellen Auffgabe damit überall
                        // bekannt ist bei welcher Aufgabe wir sind
    }  // wenn einer der ersten Aufgaben berechnet werden soll soll ein Hinweis
       // gegeben werden dass es eine weitere Aufgabe gibt
    else {
        showFinalCode();  // Aufruf der Funktion wenn die dritte Aufgabe
                          // abgeschlossen ist und das Spiel enden soll
    }
}

void showTask(int taskIndex) {
    if (isFirstTask) {
        lcd1.clear();
        lcd1.setCursor(0, 0);
        lcd1.print("Starten?");  // Fragen ob bereit um auch die Zeit berechent
                                 // werden kann
        lcd1.setCursor(0, 1);
        lcd1.print("Druecke #");         // Eingabe Signal um zustarten
        while (keypad.getKey() != '#');  // Warten, bis der Benutzer '#' drückt
        isFirstTask =
            false;  // Die Start-Aufforderung wird danach nicht mehr angezeigt
    }
    if (taskIndex <= 2) {
        startTime = millis();  // Zeitmessung
        lcd1.clear();
        lcd1.setCursor(0, 0);
        lcd1.print("Gebe dein ");
        lcd1.setCursor(0, 1);
        lcd1.print("Ergebnis ein:");  // Darstellung des Hinweisen

        Serial.println(
            "Neue Aufgabe: " +
            tasks[taskIndex]
                .question);  // Darstellung das es eine neue Aufgabe gibt
    }
}

void setup() {
    Serial.begin(9600);                    // Bautrate
    Serial.println("Programm gestartet");  // Für den Serielle Monitor
    // initalisierung der Display
    lcd1.init();
    lcd1.backlight();
    lcd2.init();
    lcd2.backlight();

    showTask(currentTask);
}

void loop() {
    char key = keypad.getKey(); //Tastenfeld eingaben einfangen

    if (key) {
        Serial.print("Taste gedrückt: "); //Ausgabe für den Seriellen Monitor
        Serial.println(key); // welche Taste wurde gedrückt

        if (key == '#') {
            Serial.print("Eingabe bestätigt: "); //Ausgabe für den Seriellen Monitor
            Serial.println(userInput); //Was eingegeben wurde

            userInput.replace(",", "."); // Umwandeln von Punkt in Komma
            float userAnswer = userInput.toFloat();  //Eingabe als eine FLießkomma stelle anzeigen
            float tolerance = 0.1; //Toleranz der Abweichung

            if (abs(userAnswer - tasks[currentTask].correctAnswer) <=
                tolerance) {
                unsigned long elapsedTime = (millis() - startTime) / 1000; //Benötigte Zeit
                lcd2.clear();
                lcd2.setCursor(0, 0);
                lcd2.print("Richtig!"); //bei korrekter EIngabe eine Info aushändigen
                lcd2.setCursor(0, 1);
                lcd2.print("Zeit: " + String(elapsedTime) + "s");//wielange die Zeit ist die gebraucht wurde
                Serial.println("Antwort ist korrekt!"); //Ausgabe für den Seriellen Monitor
                delay(3000);

                userInput = "";

                if (currentTask < 3) { // bei den ersten Beiden aufgabe zur nächsten Aufgabe verlinken
                    showNextTaskHint(currentTask); 
                    showTask(currentTask);
                } else {
                    showFinalCode(); //Methode aufrufen die das Ende einleutet
                }
                lcd2.clear();
            } else { //Sollte die Antowrt falsch sein
                lcd2.clear();
                lcd2.setCursor(0, 0);
                lcd2.print("Falsch!"); //info dass die eingabe falsch ist
                Serial.println("Antwort ist falsch!"); //Ausgabe für den Seriellen Monitor
                delay(2000);

                userInput = "";
                lcd2.clear();
            }
        } else if (key == '*') {
            if (userInput.indexOf('.') == -1) {
                userInput += ",";
                lcd2.clear();
                lcd2.setCursor(0, 0);
                lcd2.print("Eingabe:");
                lcd2.setCursor(0, 1);
                lcd2.print(userInput); //sollte ein Komma eingegeben werden dass dies korrekt aussgegebene wird
            }
        } else {
            userInput += key;
            lcd2.clear();
            lcd2.setCursor(0, 0);
            lcd2.print("Eingabe:");
            lcd2.setCursor(0, 1);
            lcd2.print(userInput); //Anzeige des Textes
        }
    }
}
