#pragma once

#include <format>
#include <memory>
#include <utility>

#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>

namespace kuiper
{

class logger {
  public:
    logger()
        : m_log(spdlog::stdout_color_st("log")) {
#if !defined(NDEBUG)
        m_log->set_level(spdlog::level::debug);
#else
        m_log->set_level(spdlog::level::info);
#endif
    }
    logger(const char* name)
        : m_log(spdlog::stdout_color_st(name)) {
#if !defined(NDEBUG)
        m_log->set_level(spdlog::level::debug);
#else
        m_log->set_level(spdlog::level::info);
#endif
    }
    ~logger() = default;

    template<typename... Args>
    inline void trace(std::format_string<Args...> fmt, Args&&... args) {
        m_log->trace(fmt, std::forward<Args>(args)...);
    }

    template<typename... Args>
    inline void debug(std::format_string<Args...> fmt, Args&&... args) {
        m_log->debug(fmt, std::forward<Args>(args)...);
    }

    template<typename... Args>
    inline void info(std::format_string<Args...> fmt, Args&&... args) {
        m_log->info(fmt, std::forward<Args>(args)...);
    }

    template<typename... Args>
    inline void warn(std::format_string<Args...> fmt, Args&&... args) {
        m_log->warn(fmt, std::forward<Args>(args)...);
    }

    template<typename... Args>
    inline void error(std::format_string<Args...> fmt, Args&&... args) {
        m_log->error(fmt, std::forward<Args>(args)...);
    }

    template<typename... Args>
    inline void critical(std::format_string<Args...> fmt, Args&&... args) {
        m_log->critical(fmt, std::forward<Args>(args)...);
    }

  private:
    std::shared_ptr<spdlog::logger> m_log {nullptr};
};

} // namespace kuiper
