#pragma once

#include <string>
#include <queue>
#include <thread>
#include <mutex>
#include <atomic>

/**
 * @brief Logger log levels
 */
enum LogLevel {
    Trace = 0,
    Debug = 1,
    Info = 2,
    Warn = 3,
    Error = 4
};

/**
 * @brief Asynchronous message logger
 */
class Logger
{
public:
    Logger(const std::string& fileName, LogLevel level = LogLevel::Info);
    ~Logger();

    Logger() = delete;
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;

    void trace(const std::string& text);
    void debug(const std::string& text);
    void info(const std::string& text);
    void warn(const std::string& text);
    void error(const std::string& text);

private:
    void writeLog() noexcept;
    void pushMessage(const std::string& text);

private:
    std::string fileName_;
    LogLevel level_;
    std::thread thread_;
    std::queue<std::string> buffer_;
    std::timed_mutex mutex_;
    std::atomic<bool> threadRunning_;
};
