#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>
#include <AFMotor.h> // Biblioteca para o shield L293D

// -------------------------------
// DEFINIÇÕES DO DISPLAY
// -------------------------------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// -------------------------------
// DEFINIÇÕES DO BLUETOOTH
// -------------------------------
#define TX 10
#define RX 11 // não usa só recebe
SoftwareSerial BT(TX, RX);

// -------------------------------
// DEFINIÇÕES DO MOTOR
// -------------------------------
AF_DCMotor motor2(2); // Motor ligado ao M2 do shield

// -------------------------------
// VARIÁVEIS GLOBAIS
// -------------------------------
String bufferBluetooth = "";  // Armazena temporariamente a string recebida
String amplitudeStr = "";     // Armazena a amplitude recebida (ex: "5.0")
int tempoMs = 0;              // Tempo (milissegundos) recebido

// -----------------------------------------------------------
// SETUP
// -----------------------------------------------------------
void setup() {
  Serial.begin(9600);

  // Inicializa display OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println("Falha ao iniciar display OLED.");
    for(;;);
  }
  display.clearDisplay();
  display.display();

  // Inicializa Bluetooth
  BT.begin(9600);

  // Inicializa motor
  motor2.setSpeed(0);
  motor2.run(RELEASE);

  Serial.println("Sistema iniciado. Formato esperado: \"amplitude;tempo\\n\"");
}

// -----------------------------------------------------------
// LOOP
// -----------------------------------------------------------
void loop() {
  // Lê dados do bluetooth. Se recebeu uma mensagem completa, faz as etapas:
  if (lerBluetooth()) {
    // Converte a amplitude string para float
    float amplitudeValor = amplitudeStr.toFloat();

    // 1) Faz COUNTDOWN de 5 até 1, com cada número centrado
    contagemDecrescenteCentrada(5);

    // 2) Mostra a amplitude (centrada) no ecrã
    mostrarMagnitudeCentrada(amplitudeValor);

    // 3) (Opcional) Liga o motor à velocidade proporcional à amplitude
    //    durante tempoMs (se não quiseres motor, apaga estas linhas).
    simulaSismo(amplitudeValor, tempoMs);
    motor2.setSpeed(0);
    motor2.run(RELEASE);

    Serial.println("Ciclo concluído. A aguardar próximo comando...");
  }
}

// -----------------------------------------------------------
// FUNÇÃO: Lê a string do Bluetooth no formato "amplitude;tempo\n"
// -----------------------------------------------------------
bool lerBluetooth() {
  while (BT.available() > 0) {
    char c = BT.read();
    if (c != '\n') {
      bufferBluetooth += c;
    } else {
      // Encontrou o fim de linha
      Serial.print("Recebido: ");
      Serial.println(bufferBluetooth);

      int separatorIndex = bufferBluetooth.indexOf(';');
      if (separatorIndex != -1) {
        amplitudeStr = bufferBluetooth.substring(0, separatorIndex);
        String tempoStr = bufferBluetooth.substring(separatorIndex + 1);
        tempoMs = tempoStr.toInt() * 1000;  // Converte em milissegundos
      }
      bufferBluetooth = "";
      return true; // Indica que recebeu uma mensagem completa
    }
  }
  return false;
}

// -----------------------------------------------------------
// FUNÇÃO: Faz um countdown (5 a 1), cada número centrado no ecrã
//         durante 1 segundo
// -----------------------------------------------------------
void contagemDecrescenteCentrada(int startNum) {
  for (int i = startNum; i >= 1; i--) {
    display.clearDisplay();
    display.setTextSize(3);  // Tamanho grande para destacar o número
    display.setTextColor(SSD1306_WHITE);

    // Converte o número i para string
    String countStr = String(i);

    // Calcula posição (x,y) para centrar horizontalmente
    // Cada dígito com textSize=3 costuma ter ~18 pixels de largura
    int16_t x = (SCREEN_WIDTH - (countStr.length() * 18)) / 2;
    int16_t y = (SCREEN_HEIGHT - (8 * 3)) / 2; 

    display.setCursor(x, y);
    display.print(countStr);
    display.display();

    delay(1000); // Espera 1 segundo entre cada número
  }
}

// -----------------------------------------------------------
// FUNÇÃO: Mostra a amplitude (magnitude) centrada no ecrã
// -----------------------------------------------------------
void mostrarMagnitudeCentrada(float amplitude) {
  display.clearDisplay();
  display.setTextSize(3);
  display.setTextColor(SSD1306_WHITE);

  // Converte amplitude para String
  String ampStr = String(amplitude, 1); // 1 casa decimal

  // Calcular posição para centrar
  int16_t x = (SCREEN_WIDTH - (ampStr.length() * 18)) / 2;
  int16_t y = (SCREEN_HEIGHT - (8 * 3)) / 2;

  display.setCursor(x, y);
  display.print(ampStr);
  display.display();
}

// -----------------------------------------------------------
// FUNÇÃO (Opcional): Liga o motor em velocidade proporcional
//                    à amplitude, durante tempoMs.
//                    (Pode ser removida se não precisares motor)
// -----------------------------------------------------------
void simulaSismo(float mag, unsigned long duracaoMs) {
  // Converte amplitude (1-10) em velocidade (0-255)
  int magInt = (int) mag; 
  int velocidade = map(magInt, 1, 10, 50, 255);

  // Garante limites
  if (velocidade < 0)   velocidade = 0;
  if (velocidade > 255) velocidade = 255;

  Serial.print("Sismo: Magnitude ");
  Serial.print(mag);
  Serial.print(" -> Velocidade do motor: ");
  Serial.println(velocidade);

  motor2.setSpeed(velocidade);
  motor2.run(FORWARD);

  delay(duracaoMs);

  Serial.println("Fim do sismo.");
}