#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // Ancho de la pantalla OLED
#define SCREEN_HEIGHT 64  // Altura de la pantalla OLED
#define OLED_RESET    -1  // Reset no es necesario para el SSD1306
#define OLED_SDA 19       // Pin SDA
#define OLED_SCL 22       // Pin SCL
#define OLED_ADDRESS 0x3C // Dirección I2C

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

#define LED_ROJO 26
#define LED_VERDE 25
#define LED_AMARILLO 21
#define LED_AZUL 17

#define BTN_ROJO 13
#define BTN_AMARILLO 5
#define BTN_VERDE 12
#define BTN_AZUL 4

#define BUZZER_PIN 15

int secuencia[100];  // Almacena la secuencia de LEDs
int entradaJugador[100];  // Almacena las entradas del jugador
int nivel = 1;  // Nivel inicial del juego
unsigned long timeout = 30000000;  // Tiempo de espera para el jugador

void setup() {
  // Inicializar el OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
    Serial.println("Error al inicializar el OLED");
    for (;;);
  }
  display.clearDisplay();  // Limpiar pantalla
  mostrarMensaje("Iniciando Juego", 2000);  // Mostrar por 2 segundos
  mostrarNivel();

  // Configurar los LEDs
  pinMode(LED_ROJO, OUTPUT);
  pinMode(LED_VERDE, OUTPUT);
  pinMode(LED_AMARILLO, OUTPUT);
  pinMode(LED_AZUL, OUTPUT);

  // Configurar los botones
  pinMode(BTN_ROJO, INPUT_PULLUP);
  pinMode(BTN_AMARILLO, INPUT_PULLUP);
  pinMode(BTN_VERDE, INPUT_PULLUP);
  pinMode(BTN_AZUL, INPUT_PULLUP);

  // Configurar el buzzer
  pinMode(BUZZER_PIN, OUTPUT);

  Serial.begin(115200);
}

void loop() {
  juegoSimonDice();
}

void sonido_buzzer(int frequency, int duration) {
  tone(BUZZER_PIN, frequency, duration);
  delay(duration);
  noTone(BUZZER_PIN);
}

void mostrarSecuencia(int nivel) {
  for (int i = 0; i < nivel; i++) {
    switch (secuencia[i]) {
      case 0:
        encender_led(LED_ROJO, 1000, 500);
        mostrarMensaje("ROJO", 500);
        break;
      case 1:
        encender_led(LED_VERDE, 1200, 500);
        mostrarMensaje("VERDE", 500);
        break;
      case 2:
        encender_led(LED_AMARILLO, 1400, 500);
        mostrarMensaje("AMARILLO", 500);
        break;
      case 3:
        encender_led(LED_AZUL, 1600, 500);
        mostrarMensaje("AZUL", 500);
        break;
    }
    delay(500);
  }
}

void encender_led(int led, int frequency, int duration) {
  digitalWrite(led, HIGH);
  sonido_buzzer(frequency, duration);
  digitalWrite(led, LOW);
}

int leerEntradaJugador() {
  unsigned long tiempo_inicial = millis();
  while (millis() - tiempo_inicial < timeout) {
    if (digitalRead(BTN_ROJO) == LOW) {
      delay(300);
      return 0;
    }
    if (digitalRead(BTN_VERDE) == LOW) {
      delay(300);
      return 1;
    }
    if (digitalRead(BTN_AMARILLO) == LOW) {
      delay(300);
      return 2;
    }
    if (digitalRead(BTN_AZUL) == LOW) {
      delay(300);
      return 3;
    }
  }
  return -1;  // Si no se presionó ningún botón
}

bool verificarEntrada(int nivel) {
  for (int i = 0; i < nivel; i++) {
    int entrada = leerEntradaJugador();
    if (entrada == -1) {
      mostrarCaritaTriste();
      Serial.println("No se presionó ningún botón a tiempo");
      return false;
    }
    entradaJugador[i] = entrada;
    if (entradaJugador[i] != secuencia[i]) {
      mostrarCaritaTriste();
      Serial.println("Error: La entrada no coincide con la secuencia");
      return false;
    }
  }
  mostrarCaritaFeliz();
  Serial.println("El jugador ingresó la secuencia correctamente");
  return true;
}

void reiniciar_juego() {
  nivel = 1;
  mostrarNivel();
}

void juegoSimonDice() {
  secuencia[nivel - 1] = random(0, 4);  // Añadir un paso a la secuencia
  Serial.print("Secuencia generada: ");
  for (int i = 0; i < nivel; i++) {
    Serial.print(secuencia[i]);
    Serial.print(" ");
  }
  Serial.println();

  mostrarSecuencia(nivel);

  if (verificarEntrada(nivel)) {
    Serial.println("¡Correcto!");
    nivel++;
    mostrarNivel();  // Actualizar la pantalla con el nuevo nivel
  } else {
    Serial.println("¡Fallaste!");
    reiniciar_juego();
  }

  delay(2000);  // Espera antes de comenzar el siguiente nivel
}

void mostrarMensaje(const char* mensaje, int tiempo) {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(mensaje);
  display.display();
  delay(tiempo);  // Mantener el mensaje en la pantalla el tiempo especificado
}

void mostrarNivel() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Nivel: ");
  display.print(nivel);
  display.display();
}

void mostrarCaritaFeliz() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(5, 10);
  display.println("Acertaste");
  display.setTextSize(1);
  display.setCursor(10, 40);

  // 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
  display.drawLine(95, 43, 97, 45, SSD1306_WHITE); // Boca feliz izquierda
  display.drawLine(97, 45, 100, 46, SSD1306_WHITE); // Boca feliz centro
  display.drawLine(100, 46, 103, 45, SSD1306_WHITE); // Boca feliz derecha

  display.display();
  delay(2000);  // Mostrar la cara feliz por 2 segundos
}

void mostrarCaritaTriste() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 5);
  display.println("Game Over");
  display.setTextSize(1);
  display.setCursor(0, 40);
  display.print("Puntaje: ");
  display.setTextSize(2);
  display.setCursor(55, 35);
  display.print(nivel - 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();
  delay(2000);  // Mostrar la cara triste por 2 segundos
}