#include "Log.h"
#include "bx/handlealloc.h"
#include "bx/hash.h"
#include "bx/timer.h"
#include <bx/string.h>
#define WIN32_LEAN_AND_MEAN
#include "Windows.h"

#include "Instance.h"

#define ESC "\x1B["
#define YELLOW ESC "33m"
#define RED ESC "31m"
#define END ESC "39m"

namespace
{
    char LineBuffer[LogInternal::MaxLineSize]{0};
    char OutBuffer[LogInternal::MaxLineSize]{0};
    bx::HandleHashMapT<1024> OnceMap;
    LogHistory History;

    constexpr char LogFormat[]{"%s\n"};
    constexpr char WarnFormat[]{YELLOW "%s" END "\n"};
    constexpr char ErrorFormat[]{RED "%s" END "\n"};
} // namespace

void Log(ELogType logType, const char* file, uint32_t line, const char* format, ...)
{
    const char* LineFormat = LogFormat;
    if (logType == ELogType::Warn) LineFormat = WarnFormat;
    if (logType == ELogType::Error) LineFormat = ErrorFormat;

    va_list args;
    va_start(args, format);
    bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, format);
    bx::vprintf(LineBuffer, args);
    bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
    va_end(args);
    OutputDebugStringA(OutBuffer);

    bx::strCopy(&History.LogBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, OutBuffer);
    History.WriteTime[History.WriteIdx] = bx::getHPCounter();
    bx::strCopy(&History.FileBuffer[History.WriteIdx * LogInternal::MaxLineSize], LogInternal::MaxLineSize, file);
    History.LineBuffer[History.WriteIdx] = line;

    ++History.WriteIdx;
    if (History.WriteIdx >= LogInternal::LogHistorySize) History.WriteIdx = 0;
}

bool WasLogged(ELogType logType, const char* file, uint32_t line, const char* format)
{
    bx::HashCrc32 hasher;
    hasher.begin();
    hasher.add(file);
    hasher.add(line);
    hasher.add(logType);
    hasher.add(format);
    uint32_t hash = hasher.end();
    if (OnceMap.find(hash) != bx::kInvalidHandle) return true;
    OnceMap.insert(hash, {});
    return false;
}

LogHistory& GetLogHistory()
{
    return History;
}
