#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <FastLED.h>
#include <driver/adc.h>
#include <esp_adc_cal.h>

// LED settings
#define NUM_LEDS 1
#define DATA_PIN 38
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

// ADC settings
#define ADC_PIN GPIO_NUM_6
#define ADC_CHANNEL ADC1_CHANNEL_5

// BLE UUIDs
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

// Global variables
BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
String currentMode = "AUTO";
uint8_t gHue = 0;
uint8_t brightness = 100;

// BLE callbacks
class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
    Serial.println("Device connected");
  }
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
    Serial.println("Device disconnected");
  }
};

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) {
    String rxValue = pCharacteristic->getValue().c_str();
    Serial.print("Received command: "); Serial.println(rxValue);
    rxValue.trim();
    if (rxValue == "M1" || rxValue == "M2" || rxValue == "M3" || rxValue == "AUTO") {
      currentMode = rxValue;
    }
  }
};

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness(brightness);

  // Setup ADC
  adc1_config_width(ADC_WIDTH_BIT_12);
  adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_DB_11);

  // BLE setup
  BLEDevice::init("ESP32_LightCtrl");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService* pService = pServer->createService(SERVICE_UUID);

  pTxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID_TX,
    BLECharacteristic::PROPERTY_NOTIFY
  );
  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic* pRxCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID_RX,
    BLECharacteristic::PROPERTY_WRITE
  );
  pRxCharacteristic->setCallbacks(new MyCallbacks());

  pService->start();
  pServer->getAdvertising()->start();
  Serial.println("Waiting for BLE client...");
}

void loop() {
  int adcValue = adc1_get_raw(ADC_CHANNEL);
  uint8_t mappedBrightness = map(adcValue, 0, 4095, 255, 20); // Inverse mapping

  if (currentMode == "AUTO") {
    brightness = mappedBrightness;
  } else if (currentMode == "M1") {
    brightness = 255; leds[0] = CRGB::Gold;
  } else if (currentMode == "M2") {
    brightness = 100; leds[0] = CRGB::SkyBlue;
  } else if (currentMode == "M3") {
    brightness = 30; leds[0] = CRGB::DarkOrange;
  }

  if (currentMode == "AUTO") {
    leds[0] = CHSV(gHue++, 255, brightness);
  }
  FastLED.setBrightness(brightness);
  FastLED.show();

  if (deviceConnected) {
    String msg = "ADC:" + String(adcValue) + " Brightness:" + String(brightness);
    pTxCharacteristic->setValue(msg.c_str());
    pTxCharacteristic->notify();
  }

  if (!deviceConnected && oldDeviceConnected) {
    delay(500);
    pServer->startAdvertising();
    oldDeviceConnected = false;
  }

  if (deviceConnected && !oldDeviceConnected) {
    oldDeviceConnected = true;
  }

  delay(100);
}
