/* KMLogger.h
 *
 * Copyright (C) 2023 OpenKylin, Inc
 */

#ifndef __LOGGER_H__
#define __LOGGER_H__

#include "KMSingleton.h"

#include <spdlog/spdlog.h>

#include <iostream>
#include <memory>

#include <stdarg.h>

#define COLOR_RED "\033[1;31m"
#define COLOR_YELLOW "\033[1;33m"
#define COLOR_RESET "\033[0m"

#define F2S()                     \
    char tmp[1024];               \
    memset(tmp, 0x00, 1024);      \
    va_list arg_list;             \
    va_start(arg_list, fmt);      \
    vsprintf(tmp, fmt, arg_list); \
    va_end(arg_list);             \
    std::string log_msg = tmp;

class KMLogger : public KMSingleton<KMLogger>
{
public:
    KMLogger(token);
    ~KMLogger();

    void setLogLevel(spdlog::level::level_enum level);
    void setLogLevel(const std::string &level);

    void inline trace(const char *fmt, ...)
    {
        F2S();
        m_logger->trace(log_msg);
        m_logger->flush();
    }

    void inline debug(const char *fmt, ...)
    {
        F2S();
        m_logger->debug(log_msg);
        m_logger->flush();
    }

    void inline info(const char *fmt, ...)
    {
        F2S();
        m_logger->info(log_msg);
        m_logger->flush();
    }

    void inline warn(const char *fmt, ...)
    {
        F2S();
        m_logger->warn(log_msg);
        m_logger->flush();
    }

    void inline error(const char *fmt, ...)
    {
        F2S();
        m_logger->error(log_msg);
        m_logger->flush();
    }

    void inline critical(const char *fmt, ...)
    {
        F2S();
        m_logger->critical(log_msg);
        m_logger->flush();
    }

    void inline pinfo(const char *fmt, ...)
    {
        F2S();
        std::cout << log_msg << std::endl;
        m_logger->info(log_msg);
        m_logger->flush();
    }

    void inline perror(const char *fmt, ...)
    {
        F2S();
        std::cout << COLOR_RED << log_msg << COLOR_RESET << std::endl;
        m_logger->error(log_msg);
        m_logger->flush();
    }

    void traceLog(const std::string &msg);
    void debugLog(const std::string &msg);
    void infoLog(const std::string &msg);
    void warnLog(const std::string &msg);
    void errorLog(const std::string &msg);
    void criticalLog(const std::string &msg);

private:
    std::string format2String(const char *fmt, ...);

private:
    std::shared_ptr<spdlog::logger> m_logger;
    spdlog::level::level_enum m_logLevel;
};

#define km_logger KMLogger::instance()

#define KMTrace(msg) KMLogger::instance().traceLog(msg)
#define KMDebug(msg) KMLogger::instance().debugLog(msg)
#define KMInfo(msg) KMLogger::instance().infoLog(msg)
#define KMWarn(msg) KMLogger::instance().warnLog(msg)
#define KMError(msg) KMLogger::instance().errorLog(msg)
#define KMCritical(msg) KMLogger::instance().criticalLog(msg)

#endif // !__LOGGER_H__
