#pragma once

#include "Arduino.h"

#define LOG_INFO(...)                        \
  {                                          \
    Logger::getInstance()->log(__VA_ARGS__); \
  }

#define LOG_TRACE(...)                       \
  {                                          \
    Logger::getInstance()->log(__VA_ARGS__); \
  }

#define LOG_WARNING(...)                     \
  {                                          \
    Logger::getInstance()->log(__VA_ARGS__); \
  }

class Logger
{
public:
  using NtpTimeT = unsigned long;

  ~Logger();

  template <class... Args>
  inline bool log(const char *formatStr, Args &&...args)
  {
    const auto time = millis();

    if (totalSize_ - currentSize_ <= sizeof(time))
      return false;

    memcpy(&data_[currentSize_], &time, sizeof(time));
    currentSize_ += time;

    const auto spaceLeft = totalSize_ - currentSize_;
    auto charsWritten = snprintf(&data_[currentSize_], spaceLeft, formatStr,
                                 std::forward<Args>(args)...);
    Serial.println(&data_[currentSize_]);

    if (charsWritten < spaceLeft)
    {
      currentSize_ += charsWritten;
      return true;
    }
    else
      return false;
  }

  static Logger *getInstance();
  static void init();
  static void setNtpTime(NtpTimeT time);

private:
  Logger();

  char *data_;
  size_t totalSize_;
  size_t currentSize_;
};
