#include "LoggerRegistry.hh"
#include "PatternMatcher.hh" 
#include <sstream>
#include <algorithm>
#include <unordered_map>
#include <cstdlib>

namespace LDASTools {
namespace AL {

// Cleanup handler for Boost.Log shutdown
static void cleanup_boost_log() {
    try {
        LoggerRegistry::shutdown();
    } catch (...) {
        // Ignore any exceptions during cleanup
    }
}

LoggerRegistry::LoggerRegistry()
    : root_node_("root") {
    // Initialize root logger
    root_node_.logger = std::make_unique<SimpleLogger>();

    // Register cleanup handler to run before static destruction
    static bool cleanup_registered = false;
    if (!cleanup_registered) {
        std::atexit(cleanup_boost_log);
        cleanup_registered = true;
    }
}

LoggerRegistry& LoggerRegistry::getInstance() {
    static LoggerRegistry* instance = new LoggerRegistry();
    // Intentionally leak the singleton to avoid static destruction order issues
    // This ensures LoggerRegistry outlives all static logger pointers
    return *instance;
}

void LoggerRegistry::shutdown() {
    // Mark SimpleLogger as shutting down to prevent any further logging
    SimpleLogger::mark_shutdown();

    // Remove all sinks to prevent logging during static destruction
    auto core = boost::log::core::get();
    core->remove_all_sinks();
    core->flush();
    // Reset the core to release resources
    core->reset_filter();
}

SimpleLogger* LoggerRegistry::get_logger(const std::string& group_name) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    if (group_name.empty() || group_name == "root") {
        return root_node_.get_or_create_logger();
    }
    
    LoggerNode* node = find_or_create_node(group_name);
    return node->get_or_create_logger();
}

void LoggerRegistry::set_group_debug_level(const std::string& group_pattern, int level) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    apply_to_matching_nodes(group_pattern, [level](LoggerNode* node) {
        node->debug_level = level;
        if (node->logger) {
            node->logger->set_debug_level(level);
        }
    });
}

void LoggerRegistry::set_group_severity(const std::string& group_pattern,
                                        SimpleLogger::custom_severity_level level) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    apply_to_matching_nodes(group_pattern, [level](LoggerNode* node) {
        node->min_severity = level;
        if (node->logger) {
            node->logger->set_min_severity(level);
        }
    });
}

void LoggerRegistry::configure_by_pattern(const std::string& pattern,
                                         std::function<void(SimpleLogger*)> configurator) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    apply_to_matching_nodes(pattern, [&configurator](LoggerNode* node) {
        if (node->logger) {
            configurator(node->logger.get());
        }
    });
}

void LoggerRegistry::enable_group(const std::string& group_pattern) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    apply_to_matching_nodes(group_pattern, [](LoggerNode* node) {
        node->enabled = true;
        if (node->logger) {
            // Re-enable by setting appropriate severity
            node->logger->set_min_severity(node->min_severity);
        }
    });
}

void LoggerRegistry::disable_group(const std::string& group_pattern) {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    apply_to_matching_nodes(group_pattern, [](LoggerNode* node) {
        node->enabled = false;
        if (node->logger) {
            // Effectively disable by setting very high severity threshold
            node->logger->set_min_severity(
                SimpleLogger::custom_severity_level(SimpleLogger::severity_level::phone));
        }
    });
}

std::vector<std::string> LoggerRegistry::get_all_logger_names() const {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    std::vector<std::string> names;
    collect_names(&root_node_, names, "");
    return names;
}

void LoggerRegistry::clear() {
    std::lock_guard<std::mutex> lock(registry_mutex_);
    
    root_node_.children.clear();
    root_node_.logger = std::make_unique<SimpleLogger>();
}

LoggerRegistry::LoggerNode* LoggerRegistry::find_or_create_node(const std::string& path) {
    std::vector<std::string> components = split_path(path);
    
    LoggerNode* current = &root_node_;
    std::string full_path;
    
    for (const auto& component : components) {
        if (!full_path.empty()) {
            full_path += ".";
        }
        full_path += component;
        
        auto it = current->children.find(component);
        if (it == current->children.end()) {
            // Create new node
            auto new_node = std::make_unique<LoggerNode>(full_path, current);
            LoggerNode* node_ptr = new_node.get();
            current->children[component] = std::move(new_node);
            current = node_ptr;
        } else {
            current = it->second.get();
        }
    }
    
    return current;
}

std::vector<std::string> LoggerRegistry::split_path(const std::string& path) const {
    std::vector<std::string> components;
    std::stringstream ss(path);
    std::string component;
    
    while (std::getline(ss, component, '.')) {
        if (!component.empty()) {
            components.push_back(component);
        }
    }
    
    return components;
}

void LoggerRegistry::apply_to_matching_nodes(const std::string& pattern,
                                            std::function<void(LoggerNode*)> func) {
    // First apply to root if it matches
    if (PatternMatcher::matches(pattern, root_node_.name)) {
        func(&root_node_);
    }
    
    // Recursively apply to children
    std::function<void(LoggerNode*)> recursive_apply = [&](LoggerNode* node) {
        for (auto& [name, child] : node->children) {
            if (PatternMatcher::matches(pattern, child->name)) {
                func(child.get());
            }
            recursive_apply(child.get());
        }
    };
    
    recursive_apply(&root_node_);
}

void LoggerRegistry::collect_names(const LoggerNode* node,
                                  std::vector<std::string>& names,
                                  const std::string& prefix) const {
    std::string current_name = prefix.empty() ? node->name : prefix + "." + node->name;
    
    if (node->logger) {
        names.push_back(current_name);
    }
    
    for (const auto& [name, child] : node->children) {
        collect_names(child.get(), names, current_name);
    }
}

SimpleLogger* LoggerRegistry::LoggerNode::get_or_create_logger() {
    if (!logger) {
        logger = std::make_unique<SimpleLogger>(name);
        apply_inherited_settings();
        
        // Apply current settings
        logger->set_debug_level(debug_level);
        logger->set_min_severity(min_severity);
        
        if (!enabled) {
            // Disable if needed
            logger->set_min_severity(
                SimpleLogger::custom_severity_level(SimpleLogger::severity_level::phone));
        }
    }
    return logger.get();
}

void LoggerRegistry::LoggerNode::apply_inherited_settings() {
    if (inherit_parent_settings && parent) {
        debug_level = parent->debug_level;
        min_severity = parent->min_severity;
        enabled = parent->enabled;
    }
}

// ScopedChannelVerbosity implementation

ScopedChannelVerbosity::ScopedChannelVerbosity(const std::string& channel, int temp_level)
    : channel_(channel), old_level_(0) {
    auto& registry = LoggerRegistry::getInstance();
    logger_ = registry.get_logger(channel);
    
    if (logger_) {
        old_level_ = logger_->get_debug_level();
        logger_->set_debug_level(temp_level);
    }
}

ScopedChannelVerbosity::~ScopedChannelVerbosity() {
    if (logger_) {
        logger_->set_debug_level(old_level_);
    }
}

} // namespace AL
} // namespace LDASTools