#pragma once
#include <cstdint>

#define LOG(fmt, ...) Log(ELogType::Log, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) Log(ELogType::Warn, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) Log(ELogType::Error, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define LOG_ONCE(fmt, ...)                                                                                             \
    if (!WasLogged(ELogType::Log, __FILE__, __LINE__, fmt))                                                            \
    {                                                                                                                  \
        Log(ELogType::Log, __FILE__, __LINE__, fmt, ##__VA_ARGS__);                                                    \
    }
#define WARN_ONCE(fmt, ...)                                                                                            \
    if (!WasLogged(ELogType::Warn, __FILE__, __LINE__, fmt))                                                           \
    {                                                                                                                  \
        Log(ELogType::Warn, __FILE__, __LINE__, fmt, ##__VA_ARGS__);                                                   \
    }
#define ERROR_ONCE(fmt, ...)                                                                                           \
    if (!WasLogged(ELogType::Error, __FILE__, __LINE__, fmt))                                                          \
    {                                                                                                                  \
        Log(ELogType::Error, __FILE__, __LINE__, fmt, ##__VA_ARGS__);                                                  \
    }

enum class ELogType
{
    Log,
    Warn,
    Error,
};

namespace LogInternal
{
    constexpr int32_t MaxLineSize = 1024;
    constexpr int32_t LogHistorySize = 1024;
} // namespace LogInternal

struct LogHistory
{
    char LogBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0};
    char FileBuffer[LogInternal::MaxLineSize * LogInternal::LogHistorySize]{0};
    uint32_t LineBuffer[LogInternal::LogHistorySize]{0};
    int32_t WriteIdx = 0;
    int64_t WriteTime[LogInternal::LogHistorySize]{0};
};

void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...);
bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format);
LogHistory& GetLogHistory();
