#include <softbus_core/logging/Logger.h>

#include <chrono>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>

namespace softbus::core {

namespace {

std::string fileStem(const char* file)
{
    if (!file || file[0] == '\0') {
        return "unknown";
    }

    const char* base = std::strrchr(file, '/');
    if (!base) {
        base = std::strrchr(file, '\\');
    }
    base = base ? base + 1 : file;

    std::string stem(base);
    const auto dot = stem.rfind('.');
    if (dot != std::string::npos) {
        stem.resize(dot);
    }
    return stem;
}

std::string formatSource(const char* file, const char* func)
{
    const std::string stem = fileStem(file);
    const char* fn = (func && func[0] != '\0') ? func : "unknown";
    return stem + "::" + fn;
}

} // namespace

Logger& Logger::instance()
{
    static Logger logger;
    return logger;
}

void Logger::setLevel(LogLevel level)
{
    std::lock_guard<std::mutex> lock(mutex_);
    level_ = level;
}

void Logger::log(LogLevel level, const char* file, const char* func, const std::string& tag,
                 const std::string& message)
{
    log(level, file, func, tag, "", message);
}

void Logger::log(LogLevel level, const char* file, const char* func, const std::string& tag,
                 const std::string& traceId, const std::string& message)
{
    (void)tag;

    if (static_cast<int>(level) < static_cast<int>(level_)) {
        return;
    }

    const char* levelStr = "INFO";
    switch (level) {
    case LogLevel::Debug: levelStr = "DEBUG"; break;
    case LogLevel::Info: levelStr = "INFO"; break;
    case LogLevel::Warn: levelStr = "WARN"; break;
    case LogLevel::Error: levelStr = "ERROR"; break;
    }

    const auto now = std::chrono::system_clock::now();
    const auto time = std::chrono::system_clock::to_time_t(now);
    std::tm tm{};
#ifdef SOFTBUS_PLATFORM_WINDOWS
    localtime_s(&tm, &time);
#else
    localtime_r(&time, &tm);
#endif

    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
        << " [" << levelStr << "] [" << formatSource(file, func) << "]";
    if (!traceId.empty()) {
        oss << "[trace=" << traceId << "]";
    }
    oss << " " << message;

    std::lock_guard<std::mutex> lock(mutex_);
    std::cerr << oss.str() << std::endl;
}

} // namespace softbus::core
