#pragma once

#ifdef USE_ESP32

#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"

#ifdef USE_ESPHOME_TASK_LOG_BUFFER
#include <cstddef>
#include <cstring>
#include <atomic>
#include <freertos/FreeRTOS.h>
#include <freertos/ringbuf.h>

namespace esphome::logger {

/**
 * @brief Task log buffer for ESP32 platform using FreeRTOS ring buffer.
 *
 * Threading Model: Multi-Producer Single-Consumer (MPSC)
 * - Multiple FreeRTOS tasks can safely call send_message_thread_safe() concurrently
 * - Only the main loop task calls borrow_message_main_loop() and release_message_main_loop()
 *
 * This uses the FreeRTOS ring buffer (RINGBUF_TYPE_NOSPLIT) which provides
 * built-in thread-safety for the MPSC pattern. The ring buffer ensures
 * message integrity - each message is stored contiguously.
 *
 * Design:
 * - Variable-size messages with header + text stored contiguously
 * - FreeRTOS ring buffer handles synchronization internally
 * - Atomic counter for fast has_messages() check without ring buffer lock
 */
class TaskLogBuffer {
 public:
  // Structure for a log message header (text data follows immediately after)
  struct LogMessage {
    const char *tag;       // We store the pointer, assuming tags are static
    char thread_name[16];  // Store thread name directly (only used for non-main threads)
    uint16_t text_length;  // Length of the message text (up to ~64KB)
    uint16_t line;         // Source code line number
    uint8_t level;         // Log level (0-7)

    // Methods for accessing message contents
    inline char *text_data() { return reinterpret_cast<char *>(this) + sizeof(LogMessage); }

    inline const char *text_data() const { return reinterpret_cast<const char *>(this) + sizeof(LogMessage); }
  };

  TaskLogBuffer();
  ~TaskLogBuffer();

  // NOT thread-safe - borrow a message from the ring buffer, only call from main loop
  bool borrow_message_main_loop(LogMessage *&message, uint16_t &text_length);

  // NOT thread-safe - release a message buffer and update the counter, only call from main loop
  void release_message_main_loop();

  // Thread-safe - send a message to the ring buffer from any thread
  bool send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
                                const char *format, va_list args);

  // Check if there are messages ready to be processed using an atomic counter for performance
  inline bool HOT has_messages() const {
    return message_counter_.load(std::memory_order_relaxed) != last_processed_counter_;
  }

  // Get the total buffer size in bytes
  static constexpr size_t size() { return ESPHOME_TASK_LOG_BUFFER_SIZE; }

 private:
  RingbufHandle_t ring_buffer_{nullptr};           // FreeRTOS ring buffer handle
  StaticRingbuffer_t structure_;                   // Static structure for the ring buffer
  uint8_t storage_[ESPHOME_TASK_LOG_BUFFER_SIZE];  // Embedded in Logger (no separate heap allocation)

  // Atomic counter for message tracking (only differences matter)
  std::atomic<uint16_t> message_counter_{0};    // Incremented when messages are committed
  mutable uint16_t last_processed_counter_{0};  // Tracks last processed message
  void *current_token_{nullptr};
};

}  // namespace esphome::logger

#endif  // USE_ESPHOME_TASK_LOG_BUFFER
#endif  // USE_ESP32
