#ifndef LDASTOOLSAL__LOGGER_REGISTRY_HH
#define LDASTOOLSAL__LOGGER_REGISTRY_HH

#include <memory>
#include <string>
#include <map>
#include <vector>
#include <mutex>
#include <functional>
#include <optional>
#include <boost/log/core.hpp>
#include "SimpleLogger.hh"

namespace LDASTools {
namespace AL {

/// @brief Registry for managing hierarchical loggers with group-based configuration
class LoggerRegistry {
public:
    /// @brief Get the singleton instance
    static LoggerRegistry& getInstance();

    /// @brief Shutdown the logging system cleanly
    /// Call this before program exit to avoid TLS errors during static destruction
    static void shutdown();

    /// @brief Get or create a logger for a specific group
    /// @param group_name Hierarchical group name (e.g., "framecpp.frtoc")
    /// @return Pointer to the logger (managed by registry)
    SimpleLogger* get_logger(const std::string& group_name);

    /// @brief Set debug level for a group pattern
    /// @param group_pattern Pattern to match (e.g., "framecpp.*")
    /// @param level Debug level to set
    void set_group_debug_level(const std::string& group_pattern, int level);

    /// @brief Set minimum severity for a group pattern
    /// @param group_pattern Pattern to match
    /// @param level Minimum severity level
    void set_group_severity(const std::string& group_pattern, 
                           SimpleLogger::custom_severity_level level);

    /// @brief Apply custom configuration to matching loggers
    /// @param pattern Pattern to match
    /// @param configurator Function to configure each matching logger
    void configure_by_pattern(const std::string& pattern,
                             std::function<void(SimpleLogger*)> configurator);

    /// @brief Enable a group of loggers
    /// @param group_pattern Pattern to match
    void enable_group(const std::string& group_pattern);

    /// @brief Disable a group of loggers
    /// @param group_pattern Pattern to match
    void disable_group(const std::string& group_pattern);

    /// @brief Get all registered logger names
    /// @return Vector of logger channel names
    std::vector<std::string> get_all_logger_names() const;

    /// @brief Clear all loggers (mainly for testing)
    void clear();

private:
    /// @brief Logger node in the hierarchy
    struct LoggerNode {
        std::string name;
        std::unique_ptr<SimpleLogger> logger;
        SimpleLogger::custom_severity_level min_severity;
        int debug_level;
        bool inherit_parent_settings;
        bool enabled;
        std::map<std::string, std::unique_ptr<LoggerNode>> children;
        LoggerNode* parent;

        LoggerNode(const std::string& n, LoggerNode* p = nullptr)
            : name(n)
            , logger(nullptr)
            , min_severity(SimpleLogger::severity_level::debug)
            , debug_level(0)
            , inherit_parent_settings(true)
            , enabled(true)
            , parent(p) {}

        /// @brief Get or create the logger instance
        SimpleLogger* get_or_create_logger();

        /// @brief Apply settings from parent if inheritance is enabled
        void apply_inherited_settings();
    };

    LoggerRegistry();
    ~LoggerRegistry() = default;

    // Disable copy and assignment
    LoggerRegistry(const LoggerRegistry&) = delete;
    LoggerRegistry& operator=(const LoggerRegistry&) = delete;

    /// @brief Find or create a node by path
    /// @param path Dot-separated path (e.g., "framecpp.frtoc")
    /// @return Pointer to the node
    LoggerNode* find_or_create_node(const std::string& path);

    /// @brief Split a path into components
    /// @param path Dot-separated path
    /// @return Vector of path components
    std::vector<std::string> split_path(const std::string& path) const;

    /// @brief Apply a function to all nodes matching a pattern
    /// @param pattern Pattern to match
    /// @param func Function to apply to each matching node
    void apply_to_matching_nodes(const std::string& pattern,
                                 std::function<void(LoggerNode*)> func);

    /// @brief Recursively collect all node names
    void collect_names(const LoggerNode* node, 
                       std::vector<std::string>& names,
                       const std::string& prefix) const;

    LoggerNode root_node_;
    mutable std::mutex registry_mutex_;
};

/// @brief RAII class for temporarily changing logger verbosity
class ScopedChannelVerbosity {
public:
    /// @brief Constructor - sets temporary debug level
    /// @param channel Channel name
    /// @param temp_level Temporary debug level
    ScopedChannelVerbosity(const std::string& channel, int temp_level);

    /// @brief Destructor - restores original level
    ~ScopedChannelVerbosity();

private:
    std::string channel_;
    int old_level_;
    SimpleLogger* logger_;
};

} // namespace AL
} // namespace LDASTools

#endif // LDASTOOLSAL__LOGGER_REGISTRY_HH