#ifndef LDASTOOLSAL__LOGGER_HH
#define LDASTOOLSAL__LOGGER_HH

#include "SimpleLogger.hh"
#include "LoggerRegistry.hh"
#include "DebugLevelManager.hh"
#include <unordered_map>
#include <mutex>
#include <atomic>

/// @brief Global flag to detect when we're in static destruction phase
/// This prevents segfaults from accessing destroyed logger objects during static destruction
namespace {
    std::atomic<bool> g_in_static_destruction{false};
    
    /// @brief RAII class to detect static destruction phase
    /// When this object is destroyed, we know we're in static destruction
    struct StaticDestructionDetector {
        ~StaticDestructionDetector() {
            g_in_static_destruction.store(true, std::memory_order_release);
        }
    };
    
    /// @brief Static instance that will be destroyed during static destruction
    /// This triggers the flag to prevent further logging during destruction
    [[maybe_unused]] static StaticDestructionDetector g_static_destruction_detector;
}

/// @brief Check if we're currently in static destruction phase
/// @return true if static destruction has begun, false otherwise
inline bool is_in_static_destruction() {
    return g_in_static_destruction.load(std::memory_order_acquire);
}

inline SimpleLogger*
default_logger( )
{
    static std::unique_ptr< SimpleLogger > simple_logger =
        std::make_unique< SimpleLogger >( );
    return simple_logger.get( );
}

// Shared cache for all channel loggers - accessible by both functions
namespace {
    std::unordered_map<std::string, SimpleLogger*>& get_logger_cache() {
        static std::unordered_map<std::string, SimpleLogger*> cache;
        return cache;
    }
    
    std::mutex& get_cache_mutex() {
        static std::mutex mutex;
        return mutex;
    }
}

/// @brief Get or create a logger for a specific channel/group
/// @param channel Channel name (e.g., "framecpp.frtoc")
/// @return Pointer to the logger
inline SimpleLogger*
get_channel_logger( const std::string& channel )
{
    std::lock_guard<std::mutex> lock(get_cache_mutex());
    
    auto& logger_cache = get_logger_cache();
    
    // Return cached logger if already configured for this channel
    auto it = logger_cache.find(channel);
    if (it != logger_cache.end()) {
        return it->second;
    }
    
    SimpleLogger* logger = LDASTools::AL::LoggerRegistry::getInstance().get_logger( channel );
    
    // Sync debug level with DebugLevelManager only during initial creation
    int effective_level = LDASTools::AL::DebugLevelManager::get_channel_level( channel );
    if (logger->get_debug_level() != effective_level) {
        logger->set_debug_level( effective_level );
    }
    
    // Cache the configured logger to prevent duplicate handler setup
    logger_cache[channel] = logger;
    
    return logger;
}

/// @brief Sync all cached loggers with current debug levels from DebugLevelManager
/// This should be called after debug levels are initialized/changed
inline void
sync_all_cached_loggers()
{
    std::lock_guard<std::mutex> lock(get_cache_mutex());
    
    auto& logger_cache = get_logger_cache();
    
    // Update all cached loggers with current debug levels
    for (const auto& pair : logger_cache) {
        const std::string& channel = pair.first;
        SimpleLogger* logger = pair.second;
        
        int effective_level = LDASTools::AL::DebugLevelManager::get_channel_level(channel);
        if (logger->get_debug_level() != effective_level) {
            logger->set_debug_level(effective_level);
        }
    }
}

/// @brief Macro for declaring static channel loggers
#define DECLARE_CHANNEL_LOGGER(name, channel) \
    inline SimpleLogger* get_##name##_logger() { \
        static SimpleLogger* logger = get_channel_logger(channel); \
        return logger; \
    }

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_debug( LOGGER_TYPE logger, int level, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_debug( level, std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_ok( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_ok( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_warning( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_warning( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_note( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_note( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_error_non_fatal( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_error_non_fatal( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_error( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_error( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_email( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_email( std::forward< Args >( args )... );
    }
}

template < typename LOGGER_TYPE, typename... Args >
void
logger_log_phone( LOGGER_TYPE logger, Args&&... args )
{
    // Early return if we're in static destruction to prevent segfaults
    if (is_in_static_destruction()) {
        return;
    }
    
    if (logger) {
        logger->log_phone( std::forward< Args >( args )... );
    }
}
#endif /* LDASTOOLSAL__LOGGER_HH */
