#ifndef UTILS_LOG_HPP
#define UTILS_LOG_HPP
#include <string>
#include <chrono>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <utils/types.hpp>
enum level : unsigned char { INFO, WARNING, ERROR, CRITICAL };
enum type : unsigned char { WEBSOCKET, NETWORK, API };
class Log {
public:
    _maybe_unused static void create(_maybe_unused const level& lvl, _maybe_unused const type& t, _maybe_unused const std::string& message) {
    #ifdef DEBUG
        std::string color;
        switch (lvl) {
            case INFO: color = "\033[34;1m"; break;
            case WARNING: color = "\033[33;1m"; break;
            case ERROR: color = "\033[31;1m"; break;
            case CRITICAL: color = "\033[31;1;2m"; break;
            default: color = "\033[0m"; break;
        }
        std::cout << color << "[" << getCurrentTime() << "][" << str(t) << "][" << str(lvl) << "] \033[0m" << message << "\033[0m" << std::endl;
    #endif
    }
    static void force_create(const level& lvl, const type& t, const std::string& message) {
        std::string color;
        switch (lvl) {
            case INFO: color = "\033[34;1m"; break;
            case WARNING: color = "\033[33;1m"; break;
            case ERROR: color = "\033[31;1m"; break;
            case CRITICAL: color = "\033[31;1;2m"; break;
            default: color = "\033[0m"; break;
        }
        std::cout << color << "[" << getCurrentTime() << "][" << str(t) << "][" << str(lvl) << "] \033[0m" << message << "\033[0m" << '\n';
    }
private:
    static auto getCurrentTime() -> const std::string {
        std::time_t now_c = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
        std::tm* timer = std::localtime(&now_c);
        std::ostringstream oss;
        oss << std::setfill('0') << std::setw(2)
            << timer->tm_hour << ":" << std::setfill('0') << std::setw(2)
            << timer->tm_min << ":" << std::setfill('0') << std::setw(2)
            << timer->tm_sec;
        return oss.str();
    }
    static auto str(const level& lvl) noexcept -> std::string {
        switch (lvl) {
        case INFO: return "INFO";
        case WARNING: return "WARNING";
        case ERROR: return "ERROR";
        case CRITICAL: return "CRITICAL";
        default: return "UNKNOWN";
        }
    }
    static auto str(const type& t) noexcept -> std::string {
        switch (t) {
        case WEBSOCKET: return "WEBSOCKET";
        case NETWORK: return "NETWORK";
        case API: return "API";
        default: return "UNKNOWN";
        }
    }
};
#endif