#include <FastLED.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>

#define NUM_LEDS 24 // Für 24 LEDs
#define LED_PIN 13
#define BUZZER_PIN 12
#define RED_BUTTON 4
#define GREEN_BUTTON 5
#define BLUE_BUTTON 18
#define YELLOW_BUTTON 19
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define MAX_SEQUENCE 50 // Maximale Sequenzlänge für Spiel 2 und 5
#define ADVERTISEMENT_TIMEOUT 30000 // 30 Sekunden Inaktivität
#define GAME_OVER_DISPLAY_TIME 10000 // 10 Sekunden für Game Over Anzeige
#define TIMING_GAME_TIMEOUT 30000 // 30 Sekunden Timeout für Spiel 3
#define DEEP_SLEEP_TIMEOUT 300000 // 5 Minuten (300.000 ms) für Deep Sleep
#define EEPROM_SIZE 21 // 5 Highscores * 4 Bytes + 1 Byte für buzzerEnabled
#define ADDR_HIGHSCORE_REACTION 0 // Adresse für Spiel 1 Highscore
#define ADDR_HIGHSCORE_MEMORY 4   // Adresse für Spiel 2 Highscore
#define ADDR_HIGHSCORE_TIMING 8   // Adresse für Spiel 3 Highscore
#define ADDR_HIGHSCORE_CHASE 12   // Adresse für Spiel 4 Highscore
#define ADDR_HIGHSCORE_RHYTHM 16  // Adresse für Spiel 5 Highscore
#define ADDR_BUZZER_ENABLED 20    // Adresse für Buzzer-Zustand
#define BUZZER_TOGGLE_HOLD_TIME 1000 // Zeit für langes Drücken (ms)
#define BUZZER_TOGGLE_OFFSET 50 // Zeitfenster für gleichzeitiges Drücken (ms)
#define HIGHSCORE_RESET_HOLD_TIME 2000 // Zeit für langes Drücken zum Highscore-Reset (ms)
#define HIGHSCORE_RESET_OFFSET 50 // Zeitfenster für gleichzeitiges Drücken (ms)

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
CRGB leds[NUM_LEDS];
int buttons[] = {RED_BUTTON, GREEN_BUTTON, BLUE_BUTTON, YELLOW_BUTTON};
CRGB colors[] = {CRGB::Red, CRGB::Green, CRGB::Blue, CRGB::Yellow};
int currentColorIndex = -1;
bool gameRunning = false;
unsigned long startTime = 0;
int sequenceCount = 0;
int reactionTime = 2000;
int currentLevel = 1;
int gameMode = 0; // 0: Kein Spiel, 1: Reaktionsspiel, 2: Farben-Memory, 3: LED-Timing, 4: LED-Lauflicht, 5: Rhythm Master
int memorySequence[MAX_SEQUENCE]; // Speicher für Farben-Memory-Sequenz
int rhythmSequence[MAX_SEQUENCE]; // Speicher für Rhythmus-Sequenz
int rhythmTones[] = {800, 1000, 1200, 1400}; // Töne für Rot, Grün, Blau, Gelb
int playerIndex = 0; // Index für Spielereingabe in Spiel 2 und 5
int ledPosition = 0; // Aktuelle Position des Lauflichts (Spiel 4)
int stepDelay = 200; // Verzögerung zwischen LED-Schritten (Spiel 4)
int rhythmTiming = 6000; // Zeitfenster für Rhythmus-Eingaben (Spiel 5)
unsigned long lastStepTime = 0; // Zeitpunkt des letzten Schritts (Spiel 4, 5)
int cycleCount = 0; // Zählt Schritte für einen vollständigen Zyklus (Spiel 4)
unsigned long lastInteractionTime = 0; // Zeitpunkt der letzten Interaktion
int targetPosition = 0; // Zufällige Position der farbigen LED (Spiel 3)
int whiteLedPosition = 0; // Position der weißen LED (Spiel 3)
unsigned long lastActionTime = 0; // Zeitpunkt des letzten Treffers oder Spielstarts (Spiel 3)
int highScoreReaction = 0; // Highscore für Spiel 1
int highScoreMemory = 0; // Highscore für Spiel 2
int highScoreTiming = 0; // Highscore für Spiel 3
int highScoreChase = 0; // Highscore für Spiel 4
int highScoreRhythm = 0; // Highscore für Spiel 5
bool buzzerEnabled = true; // Buzzer-Zustand (true = ein, false = aus)

void setup() {
  Serial.begin(115200);
  EEPROM.begin(EEPROM_SIZE);
  highScoreReaction = EEPROM.readInt(ADDR_HIGHSCORE_REACTION);
  highScoreMemory = EEPROM.readInt(ADDR_HIGHSCORE_MEMORY);
  highScoreTiming = EEPROM.readInt(ADDR_HIGHSCORE_TIMING);
  highScoreChase = EEPROM.readInt(ADDR_HIGHSCORE_CHASE);
  highScoreRhythm = EEPROM.readInt(ADDR_HIGHSCORE_RHYTHM);
  buzzerEnabled = EEPROM.readByte(ADDR_BUZZER_ENABLED) != 0;
  esp_sleep_enable_ext1_wakeup((1ULL << RED_BUTTON) | (1ULL << GREEN_BUTTON) | (1ULL << BLUE_BUTTON) | (1ULL << YELLOW_BUTTON), ESP_EXT1_WAKEUP_ANY_HIGH);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(20);
  pinMode(BUZZER_PIN, OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
  randomSeed(millis());
  clearLEDs();
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("Display Initialisierung fehlgeschlagen!");
    for (;;);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(20, 10);
  display.println("Ready!");
  display.setTextSize(1);
  display.setCursor(20, 40);
  display.println("Select Game");
  display.display();
  lastInteractionTime = millis();
}

void loop() {
  if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
    enterDeepSleep();
  }
  if (checkHighScoreReset()) {
    resetHighScores();
    return;
  }
  if (checkBuzzerToggle()) {
    toggleBuzzer();
    return;
  }
  if (!gameRunning) {
    if (millis() - lastInteractionTime > ADVERTISEMENT_TIMEOUT) {
      playAdvertisement();
    } else {
      checkForStart();
    }
  } else {
    if (gameMode == 1) {
      checkButtonsReaction();
      checkTimeoutReaction();
    } else if (gameMode == 2) {
      checkButtonsMemory();
    } else if (gameMode == 3) {
      updateColorTiming();
      checkButtonsColorTiming();
      checkTimeoutColorTiming();
    } else if (gameMode == 4) {
      updateRunningLight();
      checkButtonsRunningLight();
    } else if (gameMode == 5) {
      checkButtonsRhythm();
    }
  }
}

void enterDeepSleep() {
  Serial.println("Gehe in Deep Sleep...");
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("Entering Deep Sleep...");
  display.display();
  delay(2000);
  EEPROM.commit();
  display.clearDisplay();
  display.display();
  clearLEDs();
  esp_deep_sleep_start();
}

bool checkHighScoreReset() {
  if (digitalRead(RED_BUTTON) == LOW || digitalRead(GREEN_BUTTON) == LOW ||
      digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW) {
    unsigned long startTime = millis();
    bool redPressed = digitalRead(RED_BUTTON) == LOW;
    bool greenPressed = digitalRead(GREEN_BUTTON) == LOW;
    bool bluePressed = digitalRead(BLUE_BUTTON) == LOW;
    bool yellowPressed = digitalRead(YELLOW_BUTTON) == LOW;
    while (millis() - startTime < HIGHSCORE_RESET_OFFSET) {
      if (digitalRead(RED_BUTTON) == LOW && digitalRead(GREEN_BUTTON) == LOW &&
          digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW) {
        unsigned long holdStart = millis();
        while (millis() - holdStart < HIGHSCORE_RESET_HOLD_TIME) {
          if (digitalRead(RED_BUTTON) != LOW || digitalRead(GREEN_BUTTON) != LOW ||
              digitalRead(BLUE_BUTTON) != LOW || digitalRead(YELLOW_BUTTON) != LOW) {
            Serial.println("Buttons vorzeitig losgelassen");
            return false;
          }
          delay(10);
        }
        Serial.println("Alle Buttons für Reset erkannt");
        while (digitalRead(RED_BUTTON) == LOW || digitalRead(GREEN_BUTTON) == LOW ||
               digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
        return true;
      }
      redPressed = redPressed || (digitalRead(RED_BUTTON) == LOW);
      greenPressed = greenPressed || (digitalRead(GREEN_BUTTON) == LOW);
      bluePressed = bluePressed || (digitalRead(BLUE_BUTTON) == LOW);
      yellowPressed = yellowPressed || (digitalRead(YELLOW_BUTTON) == LOW);
      delay(10);
    }
    Serial.println("Nicht alle Buttons gedrückt");
    return false;
  }
  return false;
}

void resetHighScores() {
  highScoreReaction = 0;
  highScoreMemory = 0;
  highScoreTiming = 0;
  highScoreChase = 0;
  highScoreRhythm = 0;
  EEPROM.writeInt(ADDR_HIGHSCORE_REACTION, highScoreReaction);
  EEPROM.writeInt(ADDR_HIGHSCORE_MEMORY, highScoreMemory);
  EEPROM.writeInt(ADDR_HIGHSCORE_TIMING, highScoreTiming);
  EEPROM.writeInt(ADDR_HIGHSCORE_CHASE, highScoreChase);
  EEPROM.writeInt(ADDR_HIGHSCORE_RHYTHM, highScoreRhythm);
  EEPROM.commit();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("Highscores Reset!");
  display.display();
  delay(1000);
  if (!gameRunning) {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(2);
    display.setCursor(20, 10);
    display.println("Ready!");
    display.setTextSize(1);
    display.setCursor(20, 40);
    display.println("Select Game");
    display.display();
  } else {
    updateDisplay();
  }
  lastInteractionTime = millis();
  Serial.println("Highscores zurückgesetzt");
}

bool checkBuzzerToggle() {
  if (digitalRead(RED_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW) {
    unsigned long startTime = millis();
    bool redPressed = digitalRead(RED_BUTTON) == LOW;
    bool yellowPressed = digitalRead(YELLOW_BUTTON) == LOW;
    while (millis() - startTime < BUZZER_TOGGLE_OFFSET) {
      if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW) {
        if (BUZZER_TOGGLE_HOLD_TIME > 0) {
          unsigned long holdStart = millis();
          while (millis() - holdStart < BUZZER_TOGGLE_HOLD_TIME) {
            if (digitalRead(RED_BUTTON) != LOW || digitalRead(YELLOW_BUTTON) != LOW) {
              Serial.println("Rot + Gelb vorzeitig losgelassen");
              return false;
            }
            delay(10);
          }
        }
        Serial.println("Rot + Gelb erkannt");
        while (digitalRead(RED_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
        return true;
      }
      redPressed = redPressed || (digitalRead(RED_BUTTON) == LOW);
      yellowPressed = yellowPressed || (digitalRead(YELLOW_BUTTON) == LOW);
      delay(10);
    }
    if (redPressed && !yellowPressed) {
      Serial.println("Nur Rot gedrückt");
    } else if (yellowPressed && !redPressed) {
      Serial.println("Nur Gelb gedrückt");
    }
    return false;
  }
  return false;
}

void toggleBuzzer() {
  buzzerEnabled = !buzzerEnabled;
  EEPROM.writeByte(ADDR_BUZZER_ENABLED, buzzerEnabled ? 1 : 0);
  EEPROM.commit();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println(buzzerEnabled ? "Buzzer ON" : "Buzzer OFF");
  display.display();
  delay(1000);
  if (!gameRunning) {
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(2);
    display.setCursor(20, 10);
    display.println("Ready!");
    display.setTextSize(1);
    display.setCursor(20, 40);
    display.println("Select Game");
    display.display();
  } else {
    updateDisplay();
  }
  lastInteractionTime = millis();
  Serial.println("Buzzer-Zustand geändert: " + String(buzzerEnabled ? "ON" : "OFF"));
}

void checkForStart() {
  bool buttonPressed = false;
  if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
    Serial.println("Starte Spiel 1 (Reaction)");
    startReactionGame();
    buttonPressed = true;
    while (digitalRead(RED_BUTTON) == LOW);
  } else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
    Serial.println("Starte Spiel 2 (Memory)");
    startMemoryGame();
    buttonPressed = true;
    while (digitalRead(GREEN_BUTTON) == LOW);
  } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
    Serial.println("Starte Spiel 3 (LED Timing)");
    startColorTimingGame();
    buttonPressed = true;
    while (digitalRead(BLUE_BUTTON) == LOW);
  } else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
    Serial.println("Starte Spiel 4 (LED Chase)");
    startRunningLightGame();
    buttonPressed = true;
    while (digitalRead(YELLOW_BUTTON) == LOW);
  } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
    Serial.println("Starte Spiel 5 (Rhythm Master)");
    startRhythmGame();
    buttonPressed = true;
    while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
  }
  if (buttonPressed) {
    lastInteractionTime = millis();
    delay(50);
  }
}

void playAdvertisement() {
  int melody[] = {659, 659, 659, 523, 698, 698, 698, 587, 659, 523, 587, 494, 523, 587, 659, 698, 659, 587, 523, 494};
  int noteDurations[] = {300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500};
  int melodyLength = 20;
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("Play Now!");
  display.display();
  int currentLed = 0;
  bool isBlinkPhase = true;
  unsigned long lastLedUpdate = millis();
  int blinkDelay = 80;
  int runDelay = 120;
  int oppositeLed = NUM_LEDS / 2;
  for (int i = 0; i < melodyLength; i++) {
    if (buzzerEnabled) {
      tone(BUZZER_PIN, melody[i], noteDurations[i]);
    }
    unsigned long noteStart = millis();
    while (millis() - noteStart < noteDurations[i] + 100) {
      if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        enterDeepSleep();
      }
      if (millis() - lastLedUpdate >= (isBlinkPhase ? blinkDelay : runDelay)) {
        clearLEDs();
        if (isBlinkPhase) {
          for (int j = 0; j < NUM_LEDS; j++) {
            leds[j] = colors[random(4)];
          }
        } else {
          leds[currentLed] = colors[random(4)];
          leds[oppositeLed] = colors[random(4)];
          currentLed = (currentLed + 1) % NUM_LEDS;
          oppositeLed = (oppositeLed - 1 + NUM_LEDS) % NUM_LEDS;
        }
        FastLED.show();
        lastLedUpdate = millis();
        if ((millis() - noteStart) % 1000 < 50) {
          isBlinkPhase = !isBlinkPhase;
        }
      }
      if (checkHighScoreReset()) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        resetHighScores();
        return;
      }
      if (checkBuzzerToggle()) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        toggleBuzzer();
        return;
      }
      if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        clearLEDs();
        startReactionGame();
        while (digitalRead(RED_BUTTON) == LOW);
        lastInteractionTime = millis();
        delay(50);
        return;
      } else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        clearLEDs();
        startMemoryGame();
        while (digitalRead(GREEN_BUTTON) == LOW);
        lastInteractionTime = millis();
        delay(50);
        return;
      } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        clearLEDs();
        startColorTimingGame();
        while (digitalRead(BLUE_BUTTON) == LOW);
        lastInteractionTime = millis();
        delay(50);
        return;
      } else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        clearLEDs();
        startRunningLightGame();
        while (digitalRead(YELLOW_BUTTON) == LOW);
        lastInteractionTime = millis();
        delay(50);
        return;
      } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
        if (buzzerEnabled) noTone(BUZZER_PIN);
        clearLEDs();
        startRhythmGame();
        while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
        lastInteractionTime = millis();
        delay(500);
        return;
      }
    }
    if (buzzerEnabled) noTone(BUZZER_PIN);
  }
  clearLEDs();
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(20, 10);
  display.println("Ready!");
  display.setTextSize(1);
  display.setCursor(20, 40);
  display.println("Select Game");
  display.display();
  lastInteractionTime = millis();
}

void startReactionGame() {
  gameMode = 1;
  gameRunning = true;
  sequenceCount = 0;
  reactionTime = 2000;
  currentLevel = 1;
  updateDisplay();
  showNextColorReaction();
}

void startMemoryGame() {
  gameMode = 2;
  gameRunning = true;
  sequenceCount = 0;
  currentLevel = 1;
  playerIndex = 0;
  memorySequence[0] = random(4);
  updateDisplay();
  showMemorySequence();
}

void startColorTimingGame() {
  gameMode = 3;
  gameRunning = true;
  sequenceCount = 0;
  currentLevel = 1;
  stepDelay = 500;
  targetPosition = random(NUM_LEDS);
  currentColorIndex = random(4);
  whiteLedPosition = 0;
  lastStepTime = millis();
  lastActionTime = millis();
  updateColorTiming();
  updateDisplay();
}

void startRunningLightGame() {
  gameMode = 4;
  gameRunning = true;
  sequenceCount = 0;
  currentLevel = 1;
  ledPosition = 0;
  stepDelay = 200;
  cycleCount = 0;
  lastStepTime = millis();
  currentColorIndex = random(4);
  updateRunningLight();
  updateDisplay();
}

void startRhythmGame() {
  gameMode = 5;
  gameRunning = true;
  sequenceCount = 0;
  currentLevel = 1;
  playerIndex = 0;
  rhythmTiming = 1000;
  // Initiale Melodie: 4 zufällige Töne
  for (int i = 0; i < 4; i++) {
    rhythmSequence[i] = random(4);
  }
  updateDisplay();
  showRhythmSequence();
}

void showNextColorReaction() {
  int newColorIndex;
  do {
    newColorIndex = random(4);
  } while (newColorIndex == currentColorIndex);
  currentColorIndex = newColorIndex;
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = colors[currentColorIndex];
  }
  FastLED.show();
  if (buzzerEnabled) tone(BUZZER_PIN, 1000, 100);
  startTime = millis();
  sequenceCount++;
  updateReactionTime();
  updateDisplay();
}

void showMemorySequence() {
  for (int i = 0; i < currentLevel; i++) {
    for (int j = 0; j < NUM_LEDS; j++) {
      leds[j] = colors[memorySequence[i]];
    }
    FastLED.show();
    if (buzzerEnabled) tone(BUZZER_PIN, 1000, 100);
    delay(500);
    clearLEDs();
    delay(200);
  }
  playerIndex = 0;
}

void showRhythmSequence() {
  int sequenceLength = 4; // Feste Länge oder dynamisch: min(4 + currentLevel / 2, MAX_SEQUENCE)
  for (int i = 0; i < sequenceLength; i++) {
    for (int j = 0; j < NUM_LEDS; j++) {
      leds[j] = colors[rhythmSequence[i]];
    }
    FastLED.show();
    if (buzzerEnabled) tone(BUZZER_PIN, rhythmTones[rhythmSequence[i]], rhythmTiming / 2);
    delay(rhythmTiming / 2);
    clearLEDs();
    delay(rhythmTiming / 2);
  }
  playerIndex = 0;
  lastStepTime = millis();
}

void updateColorTiming() {
  if (millis() - lastStepTime >= stepDelay) {
    clearLEDs();
    leds[targetPosition] = colors[currentColorIndex];
    whiteLedPosition = (whiteLedPosition + 1) % NUM_LEDS;
    leds[whiteLedPosition] = CRGB::White;
    FastLED.show();
    if (buzzerEnabled) tone(BUZZER_PIN, 1000, 50);
    lastStepTime = millis();
  }
}

void updateRunningLight() {
  if (millis() - lastStepTime >= stepDelay) {
    clearLEDs();
    leds[ledPosition] = colors[currentColorIndex];
    FastLED.show();
    if (buzzerEnabled) tone(BUZZER_PIN, 1000, 50);
    ledPosition = (ledPosition + 1) % NUM_LEDS;
    cycleCount++;
    lastStepTime = millis();
    if (cycleCount >= NUM_LEDS) {
      gameOver();
    }
  }
}

void updateReactionTime() {
  if (sequenceCount <= 5) {
    reactionTime = 2000;
    currentLevel = 1;
  } else if (sequenceCount <= 10) {
    reactionTime = 1800;
    currentLevel = 2;
  } else if (sequenceCount <= 15) {
    reactionTime = 1600;
    currentLevel = 3;
  } else if (sequenceCount <= 20) {
    reactionTime = 1400;
    currentLevel = 4;
  } else if (sequenceCount <= 25) {
    reactionTime = 1200;
    currentLevel = 5;
  } else if (sequenceCount <= 30) {
    reactionTime = 1000;
    currentLevel = 6;
  } else if (sequenceCount <= 35) {
    reactionTime = 800;
    currentLevel = 7;
  } else if (sequenceCount <= 40) {
    reactionTime = 600;
    currentLevel = 8;
  } else if (sequenceCount <= 45) {
    reactionTime = 400;
    currentLevel = 9;
  } else {
    reactionTime = 200;
    currentLevel = 10;
  }
}

void checkButtonsReaction() {
  for (int i = 0; i < 4; i++) {
    if (digitalRead(buttons[i]) == LOW) {
      if (i == currentColorIndex) {
        if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
        delay(100);
        showNextColorReaction();
      } else {
        gameOver();
      }
      while (digitalRead(buttons[i]) == LOW);
      lastInteractionTime = millis();
      delay(50);
    }
  }
}

void checkButtonsMemory() {
  for (int i = 0; i < 4; i++) {
    if (digitalRead(buttons[i]) == LOW) {
      for (int j = 0; j < NUM_LEDS; j++) {
        leds[j] = colors[i];
      }
      FastLED.show();
      if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
      delay(200);
      clearLEDs();
      if (i == memorySequence[playerIndex]) {
        playerIndex++;
        if (playerIndex == currentLevel) {
          sequenceCount = currentLevel;
          currentLevel++;
          if (currentLevel <= MAX_SEQUENCE) {
            int newColor;
            do {
              newColor = random(4);
            } while (currentLevel > 1 && newColor == memorySequence[currentLevel - 2]);
            memorySequence[currentLevel - 1] = newColor;
            updateDisplay();
            delay(500);
            showMemorySequence();
          } else {
            gameOver();
          }
        }
      } else {
        gameOver();
      }
      while (digitalRead(buttons[i]) == LOW);
      lastInteractionTime = millis();
      delay(50);
    }
  }
}

void checkButtonsColorTiming() {
  for (int i = 0; i < 4; i++) {
    if (digitalRead(buttons[i]) == LOW) {
      if (i == currentColorIndex && whiteLedPosition == targetPosition) {
        if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
        sequenceCount++;
        stepDelay = max(100, stepDelay - 50);
        if (sequenceCount % 5 == 0) {
          currentLevel = sequenceCount / 5 + 1;
        }
        targetPosition = random(NUM_LEDS);
        int newColorIndex;
        do {
          newColorIndex = random(4);
        } while (newColorIndex == currentColorIndex);
        currentColorIndex = newColorIndex;
        lastActionTime = millis();
        updateDisplay();
        updateColorTiming();
      } else {
        gameOver();
      }
      while (digitalRead(buttons[i]) == LOW);
      lastInteractionTime = millis();
      delay(50);
    }
  }
}

void checkButtonsRunningLight() {
  for (int i = 0; i < 4; i++) {
    if (digitalRead(buttons[i]) == LOW) {
      if (i == currentColorIndex) {
        if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
        sequenceCount++;
        stepDelay = max(50, stepDelay - 20);
        if (sequenceCount % 5 == 0) {
          currentLevel = sequenceCount / 5 + 1;
        }
        cycleCount = 0;
        int newColorIndex;
        do {
          newColorIndex = random(4);
        } while (newColorIndex == currentColorIndex);
        currentColorIndex = newColorIndex;
        updateDisplay();
        clearLEDs();
        leds[ledPosition] = colors[currentColorIndex];
        FastLED.show();
        lastStepTime = millis();
      } else {
        gameOver();
      }
      while (digitalRead(buttons[i]) == LOW);
      lastInteractionTime = millis();
      delay(50);
    }
  }
}

void checkButtonsRhythm() {
  int sequenceLength = 4; // Feste Länge oder dynamisch: min(4 + currentLevel / 2, MAX_SEQUENCE)
  if (playerIndex < sequenceLength) {
    if (millis() - lastStepTime >= rhythmTiming) {
      gameOver(); // Timing verpasst
    }
    for (int i = 0; i < 4; i++) {
      if (digitalRead(buttons[i]) == LOW) {
        for (int j = 0; j < NUM_LEDS; j++) {
          leds[j] = colors[i];
        }
        FastLED.show();
        if (buzzerEnabled) tone(BUZZER_PIN, rhythmTones[i], 100);
        delay(200);
        clearLEDs();
        if (i == rhythmSequence[playerIndex]) {
          playerIndex++;
          if (playerIndex == sequenceLength) {
            sequenceCount++;
            rhythmTiming = max(200, rhythmTiming - 50);
            if (sequenceCount % 5 == 0) {
              currentLevel = sequenceCount / 5 + 1;
            }
            // Neue zufällige Melodie
            for (int j = 0; j < sequenceLength; j++) {
              rhythmSequence[j] = random(4);
            }
            updateDisplay();
            delay(500);
            showRhythmSequence();
          } else {
            lastStepTime = millis();
          }
        } else {
          gameOver();
        }
        while (digitalRead(buttons[i]) == LOW);
        lastInteractionTime = millis();
        delay(50);
      }
    }
  }
}

void checkTimeoutReaction() {
  if (millis() - startTime > reactionTime) {
    gameOver();
  }
}

void checkTimeoutColorTiming() {
  if (millis() - lastActionTime > TIMING_GAME_TIMEOUT) {
    gameOver();
  }
}

void showHighscoreMessage() {
  if (buzzerEnabled) {
    tone(BUZZER_PIN, 800, 200);
    delay(250);
    tone(BUZZER_PIN, 900, 300);
    delay(350);
    tone(BUZZER_PIN, 1000, 400);
    delay(450);
    tone(BUZZER_PIN, 1200, 200);
    delay(250);
    tone(BUZZER_PIN, 1400, 100);
    delay(150);
    tone(BUZZER_PIN, 1500, 100);
    delay(150);
    noTone(BUZZER_PIN);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println("New Highscore!");
  display.display();
  delay(2000);
}

void gameOver() {
  gameRunning = false;
  startTime = 0;
  int previousGameMode = gameMode;
  gameMode = 0;
  int currentScore = previousGameMode == 1 ? max(0, sequenceCount - 1) : sequenceCount;
  if (previousGameMode == 1 && currentScore > highScoreReaction) {
    highScoreReaction = currentScore;
    EEPROM.writeInt(ADDR_HIGHSCORE_REACTION, highScoreReaction);
    EEPROM.commit();
    Serial.println("Neuer Highscore Reaction: " + String(highScoreReaction));
    showHighscoreMessage();
  } else if (previousGameMode == 2 && currentScore > highScoreMemory) {
    highScoreMemory = currentScore;
    EEPROM.writeInt(ADDR_HIGHSCORE_MEMORY, highScoreMemory);
    EEPROM.commit();
    Serial.println("Neuer Highscore Memory: " + String(highScoreMemory));
    showHighscoreMessage();
  } else if (previousGameMode == 3 && currentScore > highScoreTiming) {
    highScoreTiming = currentScore;
    EEPROM.writeInt(ADDR_HIGHSCORE_TIMING, highScoreTiming);
    EEPROM.commit();
    Serial.println("Neuer Highscore Timing: " + String(highScoreTiming));
    showHighscoreMessage();
  } else if (previousGameMode == 4 && currentScore > highScoreChase) {
    highScoreChase = currentScore;
    EEPROM.writeInt(ADDR_HIGHSCORE_CHASE, highScoreChase);
    EEPROM.commit();
    Serial.println("Neuer Highscore Chase: " + String(highScoreChase));
    showHighscoreMessage();
  } else if (previousGameMode == 5 && currentScore > highScoreRhythm) {
    highScoreRhythm = currentScore;
    EEPROM.writeInt(ADDR_HIGHSCORE_RHYTHM, highScoreRhythm);
    EEPROM.commit();
    Serial.println("Neuer Highscore Rhythm: " + String(highScoreRhythm));
    showHighscoreMessage();
  }
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < NUM_LEDS; j++) {
      leds[j] = CRGB::Red;
    }
    FastLED.show();
    if (buzzerEnabled) tone(BUZZER_PIN, 500, 200);
    delay(300);
    clearLEDs();
    delay(200);
  }
  clearLEDs();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println("Game Over");
  display.setTextSize(2);
  display.setCursor(10, 16);
  display.print("Score: ");
  display.println(currentScore);
  display.setTextSize(1);
  display.setCursor(10, 36);
  display.print("Level: ");
  display.println(currentLevel);
  display.setCursor(10, 48);
  display.print("High: ");
  if (previousGameMode == 1) {
    display.println(highScoreReaction);
  } else if (previousGameMode == 2) {
    display.println(highScoreMemory);
  } else if (previousGameMode == 3) {
    display.println(highScoreTiming);
  } else if (previousGameMode == 4) {
    display.println(highScoreChase);
  } else if (previousGameMode == 5) {
    display.println(highScoreRhythm);
  }
  display.display();
  unsigned long gameOverStart = millis();
  while (millis() - gameOverStart < GAME_OVER_DISPLAY_TIME) {
    if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
      enterDeepSleep();
    }
    if (checkHighScoreReset()) {
      resetHighScores();
      return;
    }
    if (checkBuzzerToggle()) {
      toggleBuzzer();
    } else if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
      startReactionGame();
      while (digitalRead(RED_BUTTON) == LOW);
      lastInteractionTime = millis();
      delay(50);
      return;
    } else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
      startMemoryGame();
      while (digitalRead(GREEN_BUTTON) == LOW);
      lastInteractionTime = millis();
      delay(50);
      return;
    } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
      startColorTimingGame();
      while (digitalRead(BLUE_BUTTON) == LOW);
      lastInteractionTime = millis();
      delay(50);
      return;
    } else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
      startRunningLightGame();
      while (digitalRead(YELLOW_BUTTON) == LOW);
      lastInteractionTime = millis();
      delay(50);
      return;
    } else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
      startRhythmGame();
      while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
      lastInteractionTime = millis();
      delay(50);
      return;
    }
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(20, 10);
  display.println("Ready!");
  display.setTextSize(1);
  display.setCursor(20, 40);
  display.println("Select Game");
  display.display();
  lastInteractionTime = millis();
}

void clearLEDs() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black;
  }
  FastLED.show();
}

void updateDisplay() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  if (gameMode == 1) {
    display.println("Game 1: Reaction");
  } else if (gameMode == 2) {
    display.println("Game 2: Memory");
  } else if (gameMode == 3) {
    display.println("Game 3: LED Timing");
  } else if (gameMode == 4) {
    display.println("Game 4: LED Chase");
  } else if (gameMode == 5) {
    display.println("Game 5: Rhythm");
  }
  display.setTextSize(2);
  display.setCursor(10, 16);
  display.print("Score: ");
  display.println(gameMode == 1 ? sequenceCount - 1 : sequenceCount);
  display.setTextSize(1);
  display.setCursor(10, 36);
  display.print("Level: ");
  display.println(currentLevel);
  display.setCursor(10, 48);
  display.print("High: ");
  if (gameMode == 1) {
    display.println(highScoreReaction);
  } else if (gameMode == 2) {
    display.println(highScoreMemory);
  } else if (gameMode == 3) {
    display.println(highScoreTiming);
  } else if (gameMode == 4) {
    display.println(highScoreChase);
  } else if (gameMode == 5) {
    display.println(highScoreRhythm);
  }
  display.display();
}