#include "native_logger.hpp"

#include <cerrno>
#include <cstring>
#include <mutex>
#include <string>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

namespace netcore {

static std::mutex g_mu;
static int g_fd = -1;
static std::string g_path = "netcore.log";
static LogLevel g_level = LogLevel::kDebug; //LogLevel::kInfo;

static const char* level_name(LogLevel lvl) {
    switch (lvl) {
        case LogLevel::kError: return "E";
        case LogLevel::kWarn:  return "W";
        case LogLevel::kInfo:  return "I";
        case LogLevel::kDebug: return "D";
        default: return "?";
    }
}

static void ensure_open_locked() {
    if (g_path.empty()) return;
    if (g_fd >= 0) return;
    g_fd = ::open(g_path.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
}

void set_log_file(const std::string& path) {
    std::lock_guard<std::mutex> lk(g_mu);
    g_path = path;
    if (g_fd >= 0) {
        ::close(g_fd);
        g_fd = -1;
    }
    ensure_open_locked();
}

void set_log_level(LogLevel level) {
    std::lock_guard<std::mutex> lk(g_mu);
    g_level = level;
}

void log(LogLevel level, const std::string& msg) {
    std::lock_guard<std::mutex> lk(g_mu);
    if (static_cast<int>(level) > static_cast<int>(g_level)) return;
    if (g_path.empty()) return;

    ensure_open_locked();
    if (g_fd < 0) {
        // Last resort: stderr (avoid any Python APIs)
        ::write(STDERR_FILENO, msg.c_str(), msg.size());
        ::write(STDERR_FILENO, "\n", 1);
        return;
    }

    // Timestamp: epoch milliseconds (simple and cheap)
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
//    long long ms = (long long)ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
    // 1. 将秒数转换为本地时间结构体 struct tm
    struct tm *tm_info = localtime(&ts.tv_sec);

    // 2. 准备一个缓冲区来存储时间字符串
    char buffer[30];

    // 3. 格式化秒的部分
    // 格式: 年-月-日 时:分:秒
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);

    // 4. 计算毫秒部分并追加到字符串中
    // ts.tv_nsec 是纳秒，除以 1,000,000 得到毫秒
    char ms_buffer[8];
    snprintf(ms_buffer, sizeof(ms_buffer), ".%03ld", ts.tv_nsec / 1000000);

    // Build one line to keep writes atomic-ish
    char head[256];
    int n = ::snprintf(head, sizeof(head), "[%s%s] [%s] ", buffer, ms_buffer, level_name(level));
    if (n < 0) n = 0;

    ::write(g_fd, head, (size_t)n);
    ::write(g_fd, msg.c_str(), msg.size());
    ::write(g_fd, "\n", 1);
}

void log_debug(const std::string& msg) { log(LogLevel::kDebug, msg); }
void log_info (const std::string& msg) { log(LogLevel::kInfo,  msg); }
void log_warn (const std::string& msg) { log(LogLevel::kWarn,  msg); }
void log_error(const std::string& msg) { log(LogLevel::kError, msg); }

} // namespace netcore

