#include <Arduino.h>          // Librería base Arduino
#include <BluetoothSerial.h>  // Librería Bluetooth para ESP32

// =====================================================
// ================== CLASE SENSOR ======================
// =====================================================
// Esta clase representa la abstracción de un sensor.
// Encapsula la lectura del ADC (no se accede directamente al hardware desde main)
class Sensor {
  private:
    int pin;       // Pin analógico donde está conectado el sensor
    float valor;   // Valor procesado (0–100)

  public:
    // Constructor: recibe el pin de conexión
    Sensor(int p) { pin = p; }

    // Inicialización del pin
    void begin() {
      pinMode(pin, INPUT);
    }

    // Lectura del sensor
    void leer() {
      int raw = analogRead(pin);   // Lectura cruda (0–4095 en ESP32)

      // Escalado a porcentaje (0–100)
      // Esto hace que la variable sea más intuitiva para el usuario
      valor = (raw / 4095.0) * 100.0;

      // Mejora posible:
      // aplicar promedio o filtro para reducir ruido
    }

    // Getter: devuelve el valor procesado
    float getValor() {
      return valor;
    }
};

// =====================================================
// ============== CLASE CONTROL ON/OFF ==================
// =====================================================
// Implementa la lógica de control con histéresis
class ControlONOFF {
  private:
    float limInf;   // Límite inferior
    float limSup;   // Límite superior
    bool estado;    // Estado actual del sistema (ON/OFF)

  public:
    // Constructor: valores iniciales
    ControlONOFF() {
      limInf = 30;
      limSup = 70;
      estado = false;
    }

    // Permite actualizar los límites desde la app
    void setLimites(float inf, float sup) {
      limInf = inf;
      limSup = sup;
    }

    // Lógica de control
    bool actualizar(float valor) {

      // Si está por debajo del límite inferior - encender
      if (valor < limInf) estado = true;

      // Si supera el límite superior - apagar
      else if (valor > limSup) estado = false;

      // En el rango intermedio - mantiene estado (histéresis)

      return estado;
    }
};

// =====================================================
// ================= CLASE ACTUADOR =====================
// =====================================================
// Representa el actuador físico (LED o salida digital)
class Actuador {
  private:
    int pin;  // Pin de salida

  public:
    Actuador(int p) { pin = p; }

    void begin() {
      pinMode(pin, OUTPUT);
    }

    // Actualiza el estado del actuador
    void setEstado(bool estado) {
      digitalWrite(pin, estado);
    }
};

// =====================================================
// ============== CLASE COMUNICACION ====================
// =====================================================

// Objeto global de Bluetooth
BluetoothSerial SerialBT;

// Clase que encapsula la comunicación
class Comunicacion {
  public:
    // Inicializa Bluetooth
    void begin() {
      SerialBT.begin("ESP32_SCADA");  // Nombre visible para el celular
    }

    // Envío de datos hacia la app
    void enviar(float pv, bool estado) {

      // Enviar variable de proceso
      SerialBT.print("PV:");
      SerialBT.println(pv);

      // Enviar estado del sistema
      SerialBT.print("OUT:");
      SerialBT.println(estado ? 1 : 0);
    }

    // Recepción de datos desde la app
    void recibir(ControlONOFF &controlador) {

      // Verifica si hay datos disponibles
      if (SerialBT.available()) {

        // Lee hasta fin de línea
        String msg = SerialBT.readStringUntil('\n');

        msg.trim();  // elimina espacios y saltos de línea

        // Parsing simple del protocolo

        // Caso: límite inferior
        if (msg.startsWith("LIMINF:")) {
          float inf = msg.substring(7).toFloat();

          // simplificación: se mantiene el límite superior fijo
          controlador.setLimites(inf, 70);
        }

        // Caso: límite superior
        if (msg.startsWith("LIMSUP:")) {
          float sup = msg.substring(7).toFloat();

          // simplificación: se mantiene el límite inferior fijo
          controlador.setLimites(30, sup);
        }
      }
    }
};

// =====================================================
// ================= OBJETOS DEL SISTEMA ================
// =====================================================

// Se crean instancias de cada clase
Sensor sensor(34);         // ADC (potenciómetro)
ControlONOFF controlador;  // lógica de control
Actuador led(2);           // LED integrado
Comunicacion bt;           // Bluetooth

// =====================================================
// =============== VARIABLES COMPARTIDAS ================
// =====================================================

// Variables globales compartidas entre tareas
float pv = 0;       // variable de proceso
bool salida = false; // estado del sistema

// =====================================================
// ===================== TAREAS =========================
// =====================================================

// -------- TAREA DE SENSADO --------
// Lee el sensor periódicamente
void TaskSensado(void *pvParameters) {
  while (true) {
    sensor.leer();               // actualizar valor
    pv = sensor.getValor();      // guardar en variable global

    vTaskDelay(pdMS_TO_TICKS(200)); // espera 200 ms
  }
}

// -------- TAREA DE CONTROL --------
// Aplica la lógica ON/OFF
void TaskControl(void *pvParameters) {
  while (true) {
    salida = controlador.actualizar(pv); // calcula estado
    led.setEstado(salida);               // actualiza LED

    vTaskDelay(pdMS_TO_TICKS(200));
  }
}

// -------- TAREA DE COMUNICACIÓN --------
// Maneja envío y recepción
void TaskComunicacion(void *pvParameters) {
  while (true) {
    bt.enviar(pv, salida);       // envía datos a la app
    bt.recibir(controlador);     // recibe nuevos límites

    vTaskDelay(pdMS_TO_TICKS(200));
  }
}

// =====================================================
// ===================== SETUP ==========================
// =====================================================
void setup() {

  Serial.begin(115200);  // debug

  // Inicialización de módulos
  sensor.begin();
  led.begin();
  bt.begin();

  // Límites iniciales del control
  controlador.setLimites(30, 70);

  // Creación de tareas FreeRTOS sin asignar CPU específico
  //xTaskCreate(TaskSensado, "Sensado", 2048, NULL, 1, NULL);
  //xTaskCreate(TaskControl, "Control", 2048, NULL, 1, NULL);
  //xTaskCreate(TaskComunicacion, "Com", 4096, NULL, 1, NULL);


  //El ESP32 tiene 2 núcleos: Core 0 (WiFi/sistema) y Core 1 (loop/usuario)
  xTaskCreatePinnedToCore(TaskSensado, "Sensado", 2048, NULL, 1, NULL, 1);
  xTaskCreatePinnedToCore(TaskControl, "Control", 2048, NULL, 1, NULL, 1);
  xTaskCreatePinnedToCore(TaskComunicacion, "Com", 4096, NULL, 1, NULL, 0);
}

// =====================================================
// ====================== LOOP ==========================
// =====================================================
// No se utiliza el loop - sistema basado en tareas -FreeRTOS
void loop() {
}
