#ifndef BLE_PROVISIONING_H
#define BLE_PROVISIONING_H

#include "Arduino.h"
#include <NimBLEDevice.h>
#include <WString.h>
#include <stdint.h>


// BLE Service and Characteristic UUIDs
// Using standard format UUIDs for Web Bluetooth compatibility
#define SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0"
#define CHAR_WIFI_SSID_UUID "12345678-1234-5678-1234-56789abcdef1"
#define CHAR_WIFI_PASS_UUID "12345678-1234-5678-1234-56789abcdef2"
#define CHAR_DEVICE_ID_UUID "12345678-1234-5678-1234-56789abcdef3"
#define CHAR_STATUS_UUID "12345678-1234-5678-1234-56789abcdef4"
#define CHAR_STEPPER_JOG_UUID "12345678-1234-5678-1234-56789abcdef5"
#define CHAR_WIFI_SCAN_UUID                                                    \
  "12345678-1234-5678-1234-56789abcdef6" // Write 0x01 to trigger scan
#define CHAR_WIFI_RESULTS_UUID                                                 \
  "12345678-1234-5678-1234-56789abcdef7" // Read/Notify JSON results
#define CHAR_CONFIG_UUID                                                       \
  "12345678-1234-5678-1234-56789abcdef8" // Write JSON config (stepper limits)

// === Rescue Mode Characteristics ===
#define CHAR_SERIAL_OUTPUT_UUID                                                \
  "12345678-1234-5678-1234-56789abcdef9" // Read+Notify serial log stream
#define CHAR_COMMAND_UUID                                                      \
  "12345678-1234-5678-1234-56789abcdefa" // Write JSON rescue commands
#define CHAR_DIAGNOSTICS_UUID                                                  \
  "12345678-1234-5678-1234-56789abcdefb" // Read+Notify diagnostics JSON

// Status codes for BLE characteristic
#define BLE_STATUS_IDLE 0
#define BLE_STATUS_CONFIGURING 1
#define BLE_STATUS_CONNECTING 2
#define BLE_STATUS_CONNECTED 3
#define BLE_STATUS_MQTT_OK 4
#define BLE_STATUS_WIFI_FAIL 5
#define BLE_STATUS_MQTT_FAIL 6
#define BLE_STATUS_SCANNING 7       // WiFi scan in progress
#define BLE_STATUS_SCAN_DONE 8      // WiFi scan complete, results ready
#define BLE_STATUS_RESCUE_MODE 9    // Device is in rescue/recovery mode
#define BLE_STATUS_OTA_PROGRESS 10  // OTA update in progress
#define BLE_STATUS_OTA_SUCCESS 11   // OTA completed successfully
#define BLE_STATUS_OTA_FAIL 12      // OTA update failed
#define BLE_STATUS_FACTORY_RESET 13 // Factory reset in progress

// Serial capture ring buffer size (captures recent serial output for BLE streaming)
#define BLE_SERIAL_BUFFER_SIZE 2048

class BLEProvisioning {
public:
  BLEProvisioning();

  // Standard provisioning (initial setup)
  void begin();
  // Rescue mode (auto-activated when WiFi fails)
  void beginRescue();
  void stop();
  void update();

  bool isActive() const { return _active; }
  bool isRescueMode() const { return _rescueMode; }
  bool hasReceivedCredentials() const { return _credentialsReceived; }

  String getReceivedSSID() const { return _receivedSSID; }
  String getReceivedPass() const { return _receivedPass; }

  void setStatus(uint8_t status);
  void clearCredentials();

  // Get the BLE device name (e.g., "LumiBlind-A1B2C3")
  static const char *getDeviceName();

  // Stepper jog received from BLE (for calibration)
  int8_t getJogCommand() const { return _jogCommand; }
  bool hasJogCommand() const { return _jogCommandPending; }
  void clearJogCommand() { _jogCommandPending = false; }

  // WiFi scanning
  bool hasScanRequest() const { return _scanRequested; }
  void clearScanRequest() { _scanRequested = false; }
  void sendScanResults(const String &jsonResults);

  // Configuration (Servo angles, etc.)
  bool hasConfigUpdate() const { return _configUpdatePending; }
  void clearConfigUpdate() { _configUpdatePending = false; }
  String getConfigJson() const { return _receivedConfigJson; }

  // === Rescue Mode Features ===

  // Serial output streaming — captures Serial.print output and streams via BLE
  void captureSerial(const char *data, size_t len);
  void streamSerialOutput();

  // Command queue — receives JSON commands from web app
  bool hasCommand() const { return _commandPending; }
  String getCommand() const { return _receivedCommand; }
  void clearCommand() { _commandPending = false; _receivedCommand = ""; }

  // Diagnostics push — sends diagnostics JSON to connected client
  void sendDiagnostics(const String &json);

  // OTA progress — notifies client of update progress
  void sendOTAProgress(uint8_t percent, const char *statusMsg);

private:
  volatile bool _active;  // volatile: read from NimBLE host task, written from main task
  bool _rescueMode; // true if activated via rescue (not initial setup)
  bool _credentialsReceived;
  String _receivedSSID;
  String _receivedPass;

  // Stepper calibration
  int8_t _jogCommand;
  bool _jogCommandPending;

  // WiFi scanning
  bool _scanRequested;

  // === Rescue Mode State ===

  // Serial capture ring buffer
  char _serialBuffer[BLE_SERIAL_BUFFER_SIZE];
  volatile size_t _serialWritePos;
  volatile size_t _serialReadPos;
  unsigned long _lastSerialStream;

  // Command queue
  bool _commandPending;
  String _receivedCommand;

  // === BLE Handles ===
  NimBLEServer *_pServer;
  NimBLECharacteristic *_pCharSSID;
  NimBLECharacteristic *_pCharPass;
  NimBLECharacteristic *_pCharDeviceId;
  NimBLECharacteristic *_pCharStatus;
  NimBLECharacteristic *_pCharStepperJog;
  NimBLECharacteristic *_pCharWifiScan;
  NimBLECharacteristic *_pCharWifiResults;
  NimBLECharacteristic *_pCharConfig;
  // Rescue characteristics
  NimBLECharacteristic *_pCharSerialOutput;
  NimBLECharacteristic *_pCharCommand;
  NimBLECharacteristic *_pCharDiagnostics;

  void createBLECharacteristics(NimBLEService *pService);
  void _beginInternal(); // Shared init logic for begin() and beginRescue()

  friend class WiFiSSIDCallback;
  friend class WiFiPassCallback;
  friend class StepperJogCallback;
  friend class WiFiScanCallback;
  friend class ConfigCallback;
  friend class CommandCallback;
  friend class MyServerCallbacks;

  // Config storage
  bool _configUpdatePending = false;
  String _receivedConfigJson = "";
};

extern BLEProvisioning bleProvisioning;

#endif
