//
// LDASTools - Logger Manager Implementation
//
// Copyright (C) 2025 California Institute of Technology
//

#include "LoggerManager.hh"
#include <stdexcept>
#include <algorithm>

namespace LDASTools {
namespace AL {

LoggerManager::LoggerManager(boost::shared_ptr<boost::log::sinks::sink> custom_sink)
    : custom_sink_(custom_sink), sink_configured_(false) {
}

LoggerManager::~LoggerManager() {
    if (!shutdown_called_) {
        shutdown();
    }
}

SimpleLogger* LoggerManager::getLogger(const std::string& channel) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (shutdown_called_) {
        throw std::runtime_error("LoggerManager: Cannot get logger after shutdown");
    }
    
    // Configure custom sink once (using SimpleLogger's interface)
    // This ensures all loggers use the same custom sink, preventing duplication
    if (custom_sink_ && !sink_configured_) {
        // We'll configure the sink on the first logger created, which will affect all subsequent loggers
        sink_configured_ = true;
    }
    
    // Return cached logger if already exists
    auto it = loggers_.find(channel);
    if (it != loggers_.end()) {
        return it->second;
    }
    
    // PERFORMANCE OPTIMIZATION: Return nullptr for debug level 0
    // This eliminates all runtime overhead when debugging is disabled
    int effective_level = DebugLevelManager::get_channel_level(channel);
    
    if (effective_level == 0) {
        // Cache nullptr to avoid repeated level checks
        loggers_[channel] = nullptr;
        return nullptr;
    }
    
    // Create new logger using existing LoggerRegistry
    SimpleLogger* registry_logger = LoggerRegistry::getInstance().get_logger(channel);
    if (!registry_logger) {
        throw std::runtime_error("LoggerManager: Failed to create logger for channel: " + channel);
    }
    
    // Configure custom sink on the first logger if we have one
    if (custom_sink_ && loggers_.empty()) {
        registry_logger->set_custom_sink(custom_sink_);
    }
    
    // Sync debug level with DebugLevelManager during initial creation
    if (registry_logger->get_debug_level() != effective_level) {
        registry_logger->set_debug_level(effective_level);
    }
    
    // Store the logger pointer (LoggerRegistry owns the actual SimpleLogger objects)
    loggers_[channel] = registry_logger;
    
    return registry_logger;
}

void LoggerManager::syncAllLoggers() {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (shutdown_called_) {
        return; // Nothing to sync after shutdown
    }
    
    // Update all managed loggers with current debug levels
    // Need to handle transitions between nullptr (level 0) and actual loggers
    for (auto it = loggers_.begin(); it != loggers_.end(); ++it) {
        const std::string& channel = it->first;
        SimpleLogger*& logger = it->second;
        
        int effective_level = DebugLevelManager::get_channel_level(channel);
        
        if (effective_level == 0) {
            // PERFORMANCE OPTIMIZATION: Set to nullptr for debug level 0
            logger = nullptr;
        } else if (logger == nullptr) {
            // Level changed from 0 to non-zero - need to create actual logger
            SimpleLogger* registry_logger = LoggerRegistry::getInstance().get_logger(channel);
            if (registry_logger) {
                // Configure custom sink if this is the first actual logger
                if (custom_sink_ && std::none_of(loggers_.begin(), loggers_.end(), 
                    [](const auto& p) { return p.second != nullptr; })) {
                    registry_logger->set_custom_sink(custom_sink_);
                }
                
                registry_logger->set_debug_level(effective_level);
                logger = registry_logger;
            }
        } else {
            // Normal case: non-null logger, just sync level
            if (logger->get_debug_level() != effective_level) {
                logger->set_debug_level(effective_level);
            }
        }
    }
}

void LoggerManager::shutdown() {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (shutdown_called_) {
        return; // Already shut down
    }
    
    // Clear all managed logger pointers
    // Note: LoggerRegistry owns and handles the actual SimpleLogger cleanup
    loggers_.clear();
    
    shutdown_called_ = true;
}

size_t LoggerManager::getLoggerCount() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return loggers_.size();
}

} // namespace AL
} // namespace LDASTools