#ifndef DIAGNOSTICS_MANAGER_H
#define DIAGNOSTICS_MANAGER_H

#include <Arduino.h>
#include <ArduinoJson.h>
#include <stdint.h>

// ============================================================================
// Ring Buffer Sizes — kept small to minimize RAM footprint on ESP32-C6
// ============================================================================
#define DIAG_WIFI_EVENT_MAX      16
#define DIAG_MQTT_EVENT_MAX      16
#define DIAG_STEPPER_EVENT_MAX   24
#define DIAG_TOUCH_EVENT_MAX     16
#define DIAG_GENERAL_EVENT_MAX   20
#define DIAG_ERROR_EVENT_MAX     8

// ============================================================================
// Event Structures
// ============================================================================

struct WiFiEvent {
  unsigned long timestamp;    // millis()
  uint8_t reason;             // WiFi disconnect reason code
  int8_t  rssi;               // Signal strength at time of event
  char    type[8];            // "DISC", "CONN", "FAIL"
};

struct MqttEvent {
  unsigned long timestamp;
  int8_t  stateCode;          // PubSubClient state code
  char    type[8];            // "CONN", "DISC", "FAIL", "PUB_F"
};

struct StepperEvent {
  unsigned long timestamp;
  unsigned long durationMs;   // How long the move took
  int32_t startPos;           // Absolute step position
  int32_t endPos;             // Where it ended up
  int32_t targetPos;          // Where it was told to go
  uint16_t speedUsed;         // Max speed during move
  char    type[8];            // "MOVE", "JOG", "STOP", "RELAX", "STALL"
};

struct TouchEvent {
  unsigned long timestamp;
  uint16_t durationMs;        // How long the touch lasted
  char     action[12];        // "SINGLE", "DOUBLE", "FALSE", "LONG"
};

struct GeneralEvent {
  unsigned long timestamp;
  char    category[8];        // "SYS", "AUTO", "NET", "MOT"
  char    message[64];
};

struct ErrorEvent {
  unsigned long timestamp;
  char    module[8];          // "I2C", "WDT", "OTA", "MQTT", "SYS"
  char    message[48];        // Short error description
};

// ============================================================================
// Ring Buffer Template
// ============================================================================
template <typename T, size_t N>
class RingBuffer {
public:
  RingBuffer() : _head(0), _count(0) { memset(_data, 0, sizeof(_data)); }

  void push(const T& item) {
    _data[_head] = item;
    _head = (_head + 1) % N;
    if (_count < N) _count++;
  }

  // Get item by index (0 = newest)
  const T& get(size_t index) const {
    size_t idx = (_head + N - 1 - index) % N;
    return _data[idx];
  }

  size_t count() const { return _count; }
  void clear() { _head = 0; _count = 0; memset(_data, 0, sizeof(_data)); }

  // Serialize to JSON array (newest first)
  void toJson(JsonArray& arr, size_t maxItems = N) const {
    size_t limit = min(_count, maxItems);
    for (size_t i = 0; i < limit; i++) {
      const T& item = get(i);
      JsonObject obj = arr.add<JsonObject>();
      serializeItem(obj, item);
    }
  }

private:
  T _data[N];
  size_t _head;
  size_t _count;

  // Specialization via overloads
  void serializeItem(JsonObject& obj, const WiFiEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["type"] = e.type;
    obj["reason"] = e.reason;
    obj["rssi"] = e.rssi;
  }
  void serializeItem(JsonObject& obj, const MqttEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["type"] = e.type;
    obj["rc"] = e.stateCode;
  }
  void serializeItem(JsonObject& obj, const StepperEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["type"] = e.type;
    obj["from"] = e.startPos;
    obj["to"] = e.endPos;
    obj["target"] = e.targetPos;
    obj["dur"] = e.durationMs;
    obj["spd"] = e.speedUsed;
  }
  void serializeItem(JsonObject& obj, const TouchEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["action"] = e.action;
    obj["dur"] = e.durationMs;
  }
  void serializeItem(JsonObject& obj, const GeneralEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["cat"] = e.category;
    obj["msg"] = e.message;
  }
  void serializeItem(JsonObject& obj, const ErrorEvent& e) const {
    obj["t"] = e.timestamp / 1000;
    obj["mod"] = e.module;
    obj["msg"] = e.message;
  }
};

// ============================================================================
// DiagnosticsManager
// ============================================================================

class DiagnosticsManager {
public:
  DiagnosticsManager();

  // --- Event Logging (called by subsystems) ---
  void logWiFiEvent(const char* type, uint8_t reason = 0, int8_t rssi = 0);
  void logMqttEvent(const char* type, int8_t stateCode = 0);
  void logStepperEvent(const char* type, int32_t startPos, int32_t endPos,
                       int32_t targetPos, unsigned long durationMs, uint16_t speed);
  void logTouchEvent(const char* action, uint16_t durationMs);
  void logGeneralEvent(const char* category, const char* message);
  void logErrorEvent(const char* module, const char* message);

  // --- Counter Increments ---
  void incrementWiFiDisconnects() { _wifiDisconnectCount++; }
  void incrementMqttReconnects()  { _mqttReconnectCount++; }
  void incrementStepperMoves()    { _stepperMoveCount++; }
  void incrementMotorCycles()     { _motorEnableDisableCycles++; }
  void incrementTouchTotal()      { _touchTotalCount++; }
  void incrementTouchFalse()      { _touchFalseCount++; }
  void incrementPublishSuccess()  { _publishSuccessCount++; }
  void incrementPublishFail()     { _publishFailCount++; }

  // --- Build the full diagnostics JSON ---
  void buildDiagnosticsJson(JsonDocument& doc, bool verbose = false);

  // --- Reset all counters and event logs ---
  void resetAll();

  // --- Accessors ---
  uint32_t getWiFiDisconnectCount() const { return _wifiDisconnectCount; }
  uint32_t getMqttReconnectCount()  const { return _mqttReconnectCount; }
  uint32_t getStepperMoveCount()    const { return _stepperMoveCount; }
  uint32_t getTouchTotalCount()     const { return _touchTotalCount; }
  uint32_t getTouchFalseCount()     const { return _touchFalseCount; }
  uint32_t getSystemErrorCount()    const { return _errorCount; }

private:
  // Event ring buffers
  RingBuffer<WiFiEvent,    DIAG_WIFI_EVENT_MAX>    _wifiEvents;
  RingBuffer<MqttEvent,    DIAG_MQTT_EVENT_MAX>    _mqttEvents;
  RingBuffer<StepperEvent, DIAG_STEPPER_EVENT_MAX> _stepperEvents;
  RingBuffer<TouchEvent,   DIAG_TOUCH_EVENT_MAX>   _touchEvents;
  RingBuffer<GeneralEvent, DIAG_GENERAL_EVENT_MAX> _generalEvents;
  RingBuffer<ErrorEvent,   DIAG_ERROR_EVENT_MAX>   _errorEvents;

  // Cumulative counters (reset on reboot or manual reset)
  uint32_t _wifiDisconnectCount;
  uint32_t _mqttReconnectCount;
  uint32_t _stepperMoveCount;
  uint32_t _motorEnableDisableCycles;
  uint32_t _touchTotalCount;
  uint32_t _touchFalseCount;
  uint32_t _publishSuccessCount;
  uint32_t _publishFailCount;
  uint32_t _errorCount;

  // Helpers
  void buildSystemHealth(JsonObject& sys);
  void buildWiFiDiagnostics(JsonObject& wifi);
  void buildMqttDiagnostics(JsonObject& mqtt);
  void buildStepperDiagnostics(JsonObject& stepper);
  void buildTouchDiagnostics(JsonObject& touch);
  void buildAutomationDiagnostics(JsonObject& automation);
  void buildTaskSchedulerStats(JsonObject& tasks);

  const char* getResetReasonString();
};

extern DiagnosticsManager diagnosticsManager;

#endif
