#include "logger.h"
#include <iostream>
#include <ctime>

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

Logger::~Logger() {
    close();
}

void Logger::initialize(bool enableFileLogging, const std::string& logFilePath, LogLevel minLevel) {
    std::lock_guard<std::mutex> lock(m_mutex);

    m_fileLoggingEnabled = enableFileLogging;
    m_logFilePath = logFilePath;
    m_minLevel = minLevel;

    if (m_fileLoggingEnabled && !m_logFilePath.empty()) {
        m_logFile.open(m_logFilePath, std::ios::app);
        if (!m_logFile.is_open()) {
            std::cerr << "<3>ERROR: Failed to open log file: " << m_logFilePath << std::endl;
            m_fileLoggingEnabled = false;
        } else {
            // Write startup marker
            m_logFile << "\n=== Log started at " << getCurrentTimestamp() << " ===" << std::endl;
            m_logFile.flush();
        }
    }
}

void Logger::close() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_logFile.is_open()) {
        m_logFile << "=== Log closed at " << getCurrentTimestamp() << " ===" << std::endl;
        m_logFile.close();
    }
}

std::string Logger::getCurrentTimestamp() {
    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()) % 1000;

    std::tm tm_buf;
    localtime_r(&time_t_now, &tm_buf);

    std::ostringstream oss;
    oss << std::put_time(&tm_buf, "%Y-%m-%d %H:%M:%S");
    oss << '.' << std::setfill('0') << std::setw(3) << ms.count();
    return oss.str();
}

std::string Logger::levelToString(LogLevel level) {
    switch (level) {
        case LogLevel::DEBUG:   return "DEBUG";
        case LogLevel::INFO:    return "INFO";
        case LogLevel::WARNING: return "WARNING";
        case LogLevel::ERROR:   return "ERROR";
        default:                return "UNKNOWN";
    }
}

std::string Logger::levelToSystemdPriority(LogLevel level) {
    // systemd journal priority levels:
    // 0=emerg, 1=alert, 2=crit, 3=err, 4=warning, 5=notice, 6=info, 7=debug
    switch (level) {
        case LogLevel::DEBUG:   return "<7>";  // debug
        case LogLevel::INFO:    return "<6>";  // info
        case LogLevel::WARNING: return "<4>";  // warning
        case LogLevel::ERROR:   return "<3>";  // error
        default:                return "<6>";
    }
}

void Logger::log(LogLevel level, const std::string& message) {
    if (level < m_minLevel) {
        return;
    }

    std::lock_guard<std::mutex> lock(m_mutex);

    std::string timestamp = getCurrentTimestamp();
    std::string levelStr = levelToString(level);
    std::string priority = levelToSystemdPriority(level);

    // Console output with systemd priority prefix
    std::cout << priority << "[" << timestamp << "] "
              << levelStr << ": " << message << std::endl;

    // File output (without systemd priority)
    if (m_fileLoggingEnabled && m_logFile.is_open()) {
        m_logFile << "[" << timestamp << "] "
                  << levelStr << ": " << message << std::endl;
        m_logFile.flush();
    }
}
