#pragma once

#include <Core/Common/CoreTypes.h>
#include <Juliet.h>

// TODO : Juliet strings
#include <string>
// TODO Juliet Containers + Allocators...
#include <chrono>
#include <deque>

namespace Juliet
{
    enum class LogLevel : uint8;
    enum class LogCategory : uint8;

    class LogManager final
    {
      public:
        LogManager();

        void Init();
        void Shutdown();
        bool GetIsInitialized() const { return IsInitialized; }

      private:
        struct Entry
        {
            std::string                           Value;
            std::chrono::system_clock::time_point Time;
            LogLevel                              Level;
            LogCategory                           Category;

            Entry(std::string& value, LogLevel level, LogCategory category);
        };
        std::deque<Entry> Entries;
        bool              IsInitialized : 1;

        friend void Log(LogLevel level, LogCategory category, const char* fmt, va_list args);
        void        AddEntry(Entry&& entry);
        static void OutputLog(Entry& entry);
    };

    extern void JULIET_API InitializeLogManager();
    extern void JULIET_API ShutdownLogManager();
    extern void JULIET_API Log(LogLevel level, LogCategory category, const char* fmt, ...);
    extern void JULIET_API LogMessage(LogCategory category, const char* fmt, ...);
    extern void JULIET_API LogWarning(LogCategory category, const char* fmt, ...);
    extern void JULIET_API LogError(LogCategory category, const char* fmt, ...);
} // namespace Juliet
