#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1  // Pin de reset (usualmente no es necesario)

#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_ADDRESS 0x3C

// Pines de LED y botones
#define LED_VERDE 0
#define LED_BLANCO 15
#define LED_AZUL 2
#define LED_AMARILLO 19
#define LED_ROJA 23

#define BTN_VERDE 5
#define BTN_BLANCO 16
#define BTN_AZUL 17
#define BTN_AMARILLO 4
#define BTN_ROJO 18

#define SPEAKER_PIN 27

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int score = 0;
int sequence[100]; // Arreglo para almacenar la secuencia de LEDs
int userInput[100]; // Arreglo para almacenar las entradas del usuario
int level = 0; // Nivel actual del juego
int userIndex = 0; // Índice de entrada del usuario
bool gameStarted = false;
bool gameOver = false;

void setup() {
  // Inicializar pantalla OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
    while (true); // Quedarse aquí si la pantalla OLED falla
  }
  showStartScreen();
  
  // Inicializar pines de LED y botones
  pinMode(LED_VERDE, OUTPUT);
  pinMode(LED_BLANCO, OUTPUT);
  pinMode(LED_AZUL, OUTPUT);
  pinMode(LED_AMARILLO, OUTPUT);
  pinMode(LED_ROJA, OUTPUT);
  
  pinMode(BTN_VERDE, INPUT_PULLUP);
  pinMode(BTN_BLANCO, INPUT_PULLUP);
  pinMode(BTN_AZUL, INPUT_PULLUP);
  pinMode(BTN_AMARILLO, INPUT_PULLUP);
  pinMode(BTN_ROJO, INPUT_PULLUP);
  
  pinMode(SPEAKER_PIN, OUTPUT);
}

void loop() {
  if (!gameStarted && !gameOver) {
    // Esperar a que se presione cualquier botón para iniciar el juego
    if (buttonPressed()) {
      gameStarted = true;
      playStartMusic();  // Reproducir música de inicio
      delay(300); // Pequeño retraso para evitar que el primer clic cuente como jugada
      level = 1;
      addNextToSequence(); // Añadir el primer elemento a la secuencia
      playSequence();
      showClicksRemaining(level); // Mostrar la cantidad de clics que se deben hacer
    }
  } else if (gameOver) {
    // Esperar a que se presione cualquier botón para reiniciar el juego
    if (buttonPressed()) {
      resetGame();
    }
  } else {
    // Verificar si algún botón es presionado y compararlo con la secuencia
    int button = readButton();
    if (button != 0) {
      playButtonSound(button); // Reproducir sonido al presionar el botón
      handleButtonPress(button);
    }
  }
}

void playStartMusic() {
  tone(SPEAKER_PIN, 523, 200); // Nota C5
  delay(200);
  tone(SPEAKER_PIN, 587, 200); // Nota D5
  delay(200);
  tone(SPEAKER_PIN, 659, 200); // Nota E5
  delay(200);
  tone(SPEAKER_PIN, 784, 200); // Nota G5
  delay(200);
  noTone(SPEAKER_PIN);
}

void playSequence() {
  userIndex = 0;
  for (int i = 0; i < level; i++) {
    lightRandomLED(sequence[i]);
    delay(500);  // Pausa entre los LEDs
  }
}

void addNextToSequence() {
  sequence[level - 1] = random(1, 6); // Añadir un nuevo LED aleatorio a la secuencia
}

int readButton() {
  // Lee el estado de los botones y devuelve el número correspondiente
  if (digitalRead(BTN_VERDE) == LOW) {
    delay(100); // Debounce
    if (digitalRead(BTN_VERDE) == LOW) {
      return 1;
    }
  }
  if (digitalRead(BTN_BLANCO) == LOW) {
    delay(100); // Debounce
    if (digitalRead(BTN_BLANCO) == LOW) {
      return 2;
    }
  }
  if (digitalRead(BTN_AZUL) == LOW) {
    delay(100); // Debounce
    if (digitalRead(BTN_AZUL) == LOW) {
      return 3;
    }
  }
  if (digitalRead(BTN_AMARILLO) == LOW) {
    delay(100); // Debounce
    if (digitalRead(BTN_AMARILLO) == LOW) {
      return 4;
    }
  }
  if (digitalRead(BTN_ROJO) == LOW) {
    delay(100); // Debounce
    if (digitalRead(BTN_ROJO) == LOW) {
      return 5;
    }
  }
  return 0; // No se presionó ningún botón
}

void playButtonSound(int button) {
  switch (button) {
    case 1:
      tone(SPEAKER_PIN, 440, 100); // Nota A4 (La)
      break;
    case 2:
      tone(SPEAKER_PIN, 494, 100); // Nota B4 (Si)
      break;
    case 3:
      tone(SPEAKER_PIN, 523, 100); // Nota C5 (Do)
      break;
    case 4:
      tone(SPEAKER_PIN, 587, 100); // Nota D5 (Re)
      break;
    case 5:
      tone(SPEAKER_PIN, 659, 100); // Nota E5 (Mi)
      break;
  }
  delay(100);
  noTone(SPEAKER_PIN);
}

void handleButtonPress(int button) {
  userInput[userIndex] = button;
  userIndex++;
  showClicksRemaining(level - userIndex); // Actualizar y mostrar la cantidad de clics restantes

  if (userIndex == level) {
    if (checkSequence()) {
      level++;
      showHappyFace();
      delay(1000);
      addNextToSequence(); // Añadir un nuevo elemento a la secuencia
      playSequence();
      showClicksRemaining(level); // Mostrar la nueva cantidad de clics para la siguiente ronda
    } else {
      endGame();
    }
  }
}

bool checkSequence() {
  for (int i = 0; i < level; i++) {
    if (userInput[i] != sequence[i]) {
      return false;
    }
  }
  return true;
}

void lightRandomLED(int led) {
  // Apagar todos los LEDs antes de encender uno nuevo
  digitalWrite(LED_VERDE, LOW);
  digitalWrite(LED_BLANCO, LOW);
  digitalWrite(LED_AZUL, LOW);
  digitalWrite(LED_AMARILLO, LOW);
  digitalWrite(LED_ROJA, LOW);
  
  switch (led) {
    case 1:
      digitalWrite(LED_VERDE, HIGH);
      tone(SPEAKER_PIN, 261, 200); // Nota C4 (Do)
      delay(500);  // Mantener encendido el LED por 0.5 segundos
      digitalWrite(LED_VERDE, LOW);
      break;
    case 2:
      digitalWrite(LED_BLANCO, HIGH);
      tone(SPEAKER_PIN, 329, 200); // Nota E4 (Mi)
      delay(500);  // Mantener encendido el LED por 0.5 segundos
      digitalWrite(LED_BLANCO, LOW);
      break;
    case 3:
      digitalWrite(LED_AZUL, HIGH);
      tone(SPEAKER_PIN, 392, 200); // Nota G4 (Sol)
      delay(500);  // Mantener encendido el LED por 0.5 segundos
      digitalWrite(LED_AZUL, LOW);
      break;
    case 4:
      digitalWrite(LED_AMARILLO, HIGH);
      tone(SPEAKER_PIN, 523, 200); // Nota C5 (Do alto)
      delay(500);  // Mantener encendido el LED por 0.5 segundos
      digitalWrite(LED_AMARILLO, LOW);
      break;
    case 5:
      digitalWrite(LED_ROJA, HIGH);
      tone(SPEAKER_PIN, 659, 200); // Nota E5 (Mi alto)
      delay(500);  // Mantener encendido el LED por 0.5 segundos
      digitalWrite(LED_ROJA, LOW);
      break;
  }
}

void showClicksRemaining(int clicks) {
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 5);
  display.print(F("Clicks restantes: "));

  // Calcular la longitud del texto en píxeles
  int16_t textWidth = String(clicks).length() * 18; // Ancho del texto (cada dígito tiene 18 píxeles de ancho)
  int16_t posX = (128 - textWidth) / 2; // Centrar el texto (suponiendo una pantalla de 128 píxeles de ancho)
  
  display.setTextSize(4);
  display.setCursor(posX, 25); // Ajuste X para centrar, Y se mantiene en 20
  display.print(clicks);

  display.display();
}

void showHappyFace() {
  // Mostrar una cara feliz
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(5, 10);
  display.setTextSize(1);
  display.setCursor(5, 10);
  display.print(F("Muy bien"));

  // Dibujar una cara feliz
  display.drawCircle(100, 40, 10, SSD1306_WHITE); // Cabeza
  display.fillCircle(96, 38, 2, SSD1306_WHITE);  // Ojo izquierdo
  display.fillCircle(104, 38, 2, SSD1306_WHITE); // Ojo derecho

  // Boca (simplificada con una curva)
  display.drawLine(95, 43, 97, 45, SSD1306_WHITE); // Línea izquierda
  display.drawLine(97, 45, 100, 46, SSD1306_WHITE); // Línea central izquierda
  display.drawLine(100, 46, 103, 45, SSD1306_WHITE); // Línea central derecha
  display.drawLine(103, 45, 105, 43, SSD1306_WHITE); // Línea derecha

  display.display();
  
  // Reproducir música de victoria
  tone(SPEAKER_PIN, 523, 200); // Nota C5
  delay(200);
  tone(SPEAKER_PIN, 659, 200); // Nota E5
  delay(200);
  tone(SPEAKER_PIN, 784, 200); // Nota G5
  delay(200);
  noTone(SPEAKER_PIN);
}

void endGame() {
  gameOver = true;

  // Apagar todos los LEDs
  digitalWrite(LED_VERDE, LOW);
  digitalWrite(LED_BLANCO, LOW);
  digitalWrite(LED_AZUL, LOW);
  digitalWrite(LED_AMARILLO, LOW);
  digitalWrite(LED_ROJA, LOW);

  // Mostrar mensaje de Game Over y el puntaje final con una cara triste
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 5);
  display.println(F("Game Over!"));
  display.setTextSize(1);
  display.setCursor(5, 40);
  display.print(F("Total: "));
  display.setTextSize(2);
  display.setCursor(55, 35);
  display.print(level - 1);
  
  // Dibujar una cara triste
  display.drawCircle(100, 40, 10, SSD1306_WHITE); // Cabeza
  display.fillCircle(96, 38, 2, SSD1306_WHITE);  // Ojo izquierdo
  display.fillCircle(104, 38, 2, SSD1306_WHITE); // Ojo derecho
  display.drawLine(95, 44, 105, 44, SSD1306_WHITE); // Boca triste
  
  display.display();

  // Reproducir sonido de Game Over
  playGameOverTone();
}

void playGameOverTone() {
  tone(SPEAKER_PIN, 300, 500);
  delay(500);
  tone(SPEAKER_PIN, 250, 500);
  delay(500);
  tone(SPEAKER_PIN, 200, 500);
  delay(500);
}

void resetGame() {
  gameStarted = false;
  gameOver = false;
  level = 0;
  showStartScreen();
}

void showStartScreen() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 10);
  display.setTextSize(1);
  display.setCursor(5, 10);
  display.println(F("Da click en cualquier botón para iniciar"));
  display.display();
}

bool buttonPressed() {
  if (digitalRead(BTN_VERDE) == LOW || digitalRead(BTN_BLANCO) == LOW || digitalRead(BTN_AZUL) == LOW || digitalRead(BTN_AMARILLO) == LOW || digitalRead(BTN_ROJO) == LOW) {
    delay(200); // Debounce
    return true;
  }
  return false;
}