#include <ArduinoJson.hpp>
#include <ArduinoJson.h>
#include <EEPROM.h>
#include <WiFi.h>


// Dirección de memoria en la EEPROM donde se almacenará el string
#define EEPROM_ADDRESS 0
#define MAX_STRING_LENGTH 128

String ssid = "ssid_ex";
String password = "password_ex";
int pwm = 128;
String json = "";
String storedString = "";


void setup()
{
  Serial.begin(115200);

  if (mostrarMenuInicio()){menuInicio();}
  readParams();



}

void loop()
{


}


/* ------------------------------------------------------------
   FUNCIONES DE APOYO AL PROGRAMA PRINCIPAL
   -------------------------------------------------------------*/

/* Funcion que consulta si se muestra el "Menu de Inicio" */
bool mostrarMenuInicio() {
  Serial.print("¿Desea modificar la configuración? (s/n): ");
  unsigned long startTime = millis();
  char userInput = ' ';

  while (millis() - startTime < 10000) {
    Serial.print("#");
    delay(1000); // Esperar 1 segundo antes de volver a verificar
    if (Serial.available()) {
      userInput = Serial.read();
      if (userInput == 's' || userInput == 'n') {
        return (userInput == 's');
      }
    }
  }
  return false; // Si no se presionó 's' en 10 segundos, no mostrar el menú.
}


/* Menu de Inicio */
void menuInicio()
{
  char flag = 's';

  while (flag == 's')
  {
    Serial.println("Menú de modificación de parámetros:");
    Serial.println("1. Modificar SSID: " + ssid);
    Serial.println("2. Modificar Password: " + password);
    Serial.println("3. Modificar PWM: " + String(pwm));
    Serial.println("4. Guardar cambios y salir");
    Serial.println("5. Salir sin guardar cambios");

    Serial.print("Seleccione una opción (1-5): ");
    if (Serial.available()>0){Serial.read();}
    while (!Serial.available()) {}

    int option = Serial.parseInt();
    Serial.println(option);

    switch (option)
    { 
      case 1:
        Serial.print("Nuevo SSID: ");
        while (Serial.available()<2) {}
        ssid = Serial.readString();
        ssid.trim();
        Serial.println(ssid);
        break;
      
      case 2:
        Serial.print("Nueva Password: ");
        while (Serial.available()<2) {}
        password = Serial.readString();
        password.trim();
        Serial.println(password);
        break;

      case 3:
        Serial.print("Nuevo PWM: ");
        if (Serial.available()>0){Serial.read();}
        while (!Serial.available()) {}
        pwm = Serial.parseInt();
        Serial.println(pwm);
        break;

      case 4:
        json = jsonSerialize(ssid, password, pwm);
        EEPROM.writeString(EEPROM_ADDRESS, json);
        EEPROM.commit();
        Serial.println("Salir y guardar cambios en la EEPROM.");
        flag = 'n';
        break;

      case 5:
        Serial.println("Salir sin guardar cambios.");
        flag = 'n';
        break;

      default:
        Serial.println("Opción no válida. Intente de nuevo.");
        break;
    }

    if (flag == 's'){
      Serial.println("¿Desea modificar otro parámetro? (s/n): ");
      if (Serial.available()>0){Serial.read();}
      while (!Serial.available()){}
      char userInput = Serial.read();

      if (userInput == 'n'){
        json = jsonSerialize(ssid, password, pwm);
        EEPROM.writeString(EEPROM_ADDRESS, json);
        EEPROM.commit();
        Serial.println("Salir y guardar cambios en la EEPROM.");
        flag = 'n';
      } 
    }
  }
}


/* Lectura de Parametros iniciales */
void readParams(){
  jsonDeserialize(eepromRead());
  Serial.println("Configuración cargada desde la EEPROM:");
  Serial.println("SSID: " + ssid);
  Serial.println("Password: " + password);
  Serial.println("PWM: " + String(pwm));
}


/* Función que lee los parametros en la EEPROM */
String eepromRead()
{
  if (!EEPROM.begin(MAX_STRING_LENGTH)) {
    Serial.println("Error al inicializar la EEPROM.");
    Serial.println("Reiniciando...");
    delay(1000);
    ESP.restart();
  } else {
    Serial.println("Lectura correcta de EEPROM.");
  }

  // Intenta leer el string de la EEPROM
  String string_stored = EEPROM.readString(EEPROM_ADDRESS);
  Serial.println("Contenido en la EEPROM:");
  Serial.println(string_stored);

  return string_stored;
}


/* Función que serializa los parametros en un string*/
String jsonSerialize(String ssid_loc, String password_loc, int pwm_loc)
{
  String json_loc;
  StaticJsonDocument<MAX_STRING_LENGTH> doc;
  doc["ssid"] = ssid_loc;
  doc["password"] = password_loc;
  doc["pwm"] = pwm_loc;
  serializeJson(doc, json_loc);
  Serial.println(json_loc);

  return json_loc;
}


/* Función que deserializa los parametro y actualiza las variables */
void jsonDeserialize(String json_loc)
{
  StaticJsonDocument<MAX_STRING_LENGTH> doc;
  DeserializationError error = deserializeJson(doc, json_loc);
  if (error) {
    // Manejo de errores si la deserialización falla
    Serial.println("Error al deserializar JSON.");
    return;
  }

  const char* ssidChar = doc["ssid"];
  const char* passwordChar = doc["password"];

  // Convertir los valores a String
  ssid = String(ssidChar);
  password = String(passwordChar);
  pwm = doc["pwm"];

  Serial.println("Valores deserializados:");
  Serial.println("SSID: " + ssid);
  Serial.println("Password: " + password);
  Serial.println("PWM: " + String(pwm));
}