#include <BLEDevice.h>
#include <BLEClient.h>
#include <WiFi.h>
#include <WebServer.h>

// ── Configuración ──────────────────────────────────────────────
const char* WIFI_SSID = "MOVISTAR_1110";
const char* WIFI_PASS = "Yess.1990";

const char* BLE_NAME  = "elk-bleddm";   // nombre del controlador LED

// UUIDs del protocolo ELK-BLEDOM
static BLEUUID serviceUUID("0000fff0-0000-1000-8000-00805f9b34fb");
static BLEUUID    writeUUID("0000fff3-0000-1000-8000-00805f9b34fb");
// ───────────────────────────────────────────────────────────────

WebServer server(80);
BLEClient*           bleClient    = nullptr;
BLERemoteCharacteristic* bleWrite = nullptr;
bool bleConnected = false;

// Envía 9 bytes al controlador LED
void sendCmd(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
             uint8_t b5, uint8_t b6, uint8_t b7) {
  if (!bleConnected || !bleWrite) return;
  uint8_t cmd[9] = { 0x7e, b1, b2, b3, b4, b5, b6, b7, 0xef };
  bleWrite->writeValue(cmd, 9);
}

void ledOn()                           { sendCmd(0x00, 0x04, 0xf0, 0x00, 0x01, 0xff, 0x00); }
void ledOff()                          { sendCmd(0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00); }
void ledColor(uint8_t r, uint8_t g, uint8_t b) { sendCmd(0x00, 0x05, 0x03, r, g, b, 0x00); }
void ledBrillo(uint8_t v)              { sendCmd(0x04, 0x01, v,    0x01, 0xff, 0x02, 0x01); }

// Cabeceras CORS para que led.html pueda llamar desde otra IP
void cors() {
  server.sendHeader("Access-Control-Allow-Origin", "*");
  server.sendHeader("Access-Control-Allow-Methods", "GET");
}

void setupRoutes() {
  server.on("/on", []() {
    cors(); ledOn();
    server.send(200, "text/plain", "ON");
  });
  server.on("/off", []() {
    cors(); ledOff();
    server.send(200, "text/plain", "OFF");
  });
  server.on("/color", []() {
    cors();
    if (server.hasArg("r") && server.hasArg("g") && server.hasArg("b")) {
      uint8_t r = server.arg("r").toInt();
      uint8_t g = server.arg("g").toInt();
      uint8_t b = server.arg("b").toInt();
      ledColor(r, g, b);
      server.send(200, "text/plain", "Color OK");
    } else {
      server.send(400, "text/plain", "Faltan r,g,b");
    }
  });
  server.on("/brillo", []() {
    cors();
    if (server.hasArg("v")) {
      uint8_t v = constrain(server.arg("v").toInt(), 1, 100);
      ledBrillo(v);
      server.send(200, "text/plain", "Brillo OK");
    } else {
      server.send(400, "text/plain", "Falta v");
    }
  });
  server.on("/status", []() {
    cors();
    server.send(200, "text/plain", bleConnected ? "BLE:OK" : "BLE:desconectado");
  });
}

bool conectarBLE() {
  Serial.println("Buscando " + String(BLE_NAME) + "...");
  BLEScan* scan = BLEDevice::getScan();
  scan->setActiveScan(true);
  BLEScanResults* results = scan->start(5, false);

  BLEAddress ledAddr("");
  bool found = false;
  for (int i = 0; i < results->getCount(); i++) {
    BLEAdvertisedDevice dev = results->getDevice(i);
    if (dev.getName() == BLE_NAME) {
      ledAddr = dev.getAddress();
      found = true;
      Serial.print("Encontrado: ");
      Serial.println(ledAddr.toString().c_str());
      break;
    }
  }
  scan->clearResults();
  if (!found) return false;

  bleClient = BLEDevice::createClient();
  if (!bleClient->connect(ledAddr)) return false;

  BLERemoteService* svc = bleClient->getService(serviceUUID);
  if (!svc) { bleClient->disconnect(); return false; }

  bleWrite = svc->getCharacteristic(writeUUID);
  if (!bleWrite) { bleClient->disconnect(); return false; }

  bleConnected = true;
  Serial.println("BLE conectado");
  return true;
}

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

  BLEDevice::init("ESP32-LED");

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("WiFi...");
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
  Serial.println("\nIP: " + WiFi.localIP().toString());

  conectarBLE();

  setupRoutes();
  server.begin();
  Serial.println("HTTP servidor listo");
}

void loop() {
  server.handleClient();

  // Reconexión BLE si se pierde
  if (!bleConnected || (bleClient && !bleClient->isConnected())) {
    bleConnected = false;
    delay(3000);
    conectarBLE();
  }
}
