#pragma once

#include "spdlog/spdlog.h"
#include "source_location.h"
#include <cstdint>
#include <stdexcept>
namespace zlog {
    using level_enum = spdlog::level::level_enum;
    class zloger {
    private:
        std::shared_ptr<spdlog::logger> m_logger;
    public:
        zloger();
        ~zloger();
        template <typename... Args>
        void log(level_enum level, format_with_location& fmt, Args &&...args) {
            m_logger->log(fmt.loc, level, fmt::runtime(fmt.value), std::forward<Args>(args)...);
        }
        void flush() {
            m_logger->flush();
        }
    };
    extern zloger zlog;
    template <typename... Args>
    void info(format_with_location fmt, Args &&...args) {
        zlog.log(level_enum::info, fmt, std::forward<Args>(args)...);
    };
    template <typename... Args>
    void debug(format_with_location fmt, Args &&...args) {
        zlog.log(level_enum::debug, fmt, std::forward<Args>(args)...);
    };
    template <typename... Args>
    void warn(format_with_location fmt, Args &&...args) {
        zlog.log(level_enum::warn, fmt, std::forward<Args>(args)...);
    };
    template <typename... Args>
    void error(format_with_location fmt, Args &&...args) {
        zlog.log(level_enum::err, fmt, std::forward<Args>(args)...);
    };
    template <typename... Args>
    void fatal(format_with_location fmt, Args &&...args) {
        zlog.log(level_enum::critical, fmt, std::forward<Args>(args)...);
        const std::string format_str = fmt::format(std::forward<Args>(args)...);
        throw std::runtime_error(format_str);
    };
    void flush();
};