#ifndef SIMPLE_LOGGER_HH
#define SIMPLE_LOGGER_HH

#define BOOST_LOG_DYN_LINK 1

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/syslog_backend.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/attributes/constant.hpp>
#include <boost/log/attributes/attribute_set.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/sinks/frontend_requirements.hpp>
#include <iostream>
#include <fstream>
#include <mutex>
#include <sstream>
#include <memory>
#include <stdexcept>
#include <filesystem>
#include <vector>
#include <functional>

/// @brief SimpleLogger class for logging.
class SimpleLogger
{
private:
    static bool shutdown_initiated_;  // Track if logging system is shutting down
    
public:
    /// @brief Mark the logging system as shutting down
    static void mark_shutdown() { shutdown_initiated_ = true; }
    
    /// @brief Check if logging system is shutting down
    static bool is_shutdown() { return shutdown_initiated_; }
    /// @brief Custom severity levels.
    enum class severity_level
    {
        debug, ///< Debug level
        ok, ///< Normal completion
        note, ///< Note level
        warning, ///< Warning level
        error_non_fatal, ///< Non-fatal error level
        error, ///< Error level
        email, ///< Email level
        phone ///< Phone level
    };

    /// @brief Struct to handle both integer debug levels and severity enums.
    struct custom_severity_level
    {
        int            debug_level; ///< Debug level as integer
        severity_level severity; ///< Severity level as enum

        /// @brief Default constructor.
        custom_severity_level( )
            : debug_level( 0 ), severity( severity_level::debug )
        {
        }

        /// @brief Constructor for integer debug level.
        /// @param level Debug level as integer
        custom_severity_level( int level )
            : debug_level( level ), severity( severity_level::debug )
        {
        }

        /// @brief Constructor for severity enum.
        /// @param sev Severity level as enum
        custom_severity_level( severity_level sev )
            : debug_level( -1 ), severity( sev )
        {
        }

        /// @brief Comparison operator for logging level ordering.
        /// @param other Another custom_severity_level object
        /// @return True if current object is less than the other
        bool
        operator<( const custom_severity_level& other ) const
        {
            if ( debug_level >= 0 && other.debug_level >= 0 )
            {
                return debug_level < other.debug_level;
            }
            return severity < other.severity;
        }

        /// @brief Comparison operator for logging level ordering.
        /// @param other Another custom_severity_level object
        /// @return True if current object is less than or equal to the other
        bool
        operator<=( const custom_severity_level& other ) const
        {
            return *this < other || *this == other;
        }

        /// @brief Comparison operator for logging level ordering.
        /// @param other Another custom_severity_level object
        /// @return True if current object is greater than or equal to the other
        bool
        operator>=( const custom_severity_level& other ) const
        {
            return !( *this < other );
        }

        /// @brief Equality operator for custom_severity_level.
        /// @param other Another custom_severity_level object
        /// @return True if both objects are equal
        bool
        operator==( const custom_severity_level& other ) const
        {
            return debug_level == other.debug_level &&
                severity == other.severity;
        }
    };

    /// @brief Format type for log output.
    enum class FormatType
    {
        Text,
        HTML
    };

    /// @brief Constructor for SimpleLogger.
    /// @param channel Optional channel name for hierarchical logging
    SimpleLogger( const std::string& channel = "root" );

    /// @brief Log a debug message with integer level.
    /// @tparam Args Variadic template for message parts
    /// @param level Debug level as integer
    /// @param args Message parts
    template < typename... Args >
    void log_debug( int level, Args&&... args );

    /// @brief Log a warning message.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_warning( Args&&... args );

    /// @brief Log an ok message.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_ok( Args&&... args );

    /// @brief Log a note message.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_note( Args&&... args );

    /// @brief Log a non-fatal error message.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_error_non_fatal( Args&&... args );

    /// @brief Log an error message.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_error( Args&&... args );

    /// @brief Log an email alert.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_email( Args&&... args );

    /// @brief Log a phone alert.
    /// @tparam Args Variadic template for message parts
    /// @param args Message parts
    template < typename... Args >
    void log_phone( Args&&... args );

    /// @brief Set the debug level.
    /// @param level Debug level as integer
    void set_debug_level( int level );

    /// @brief Set the minimal severity level for logging.
    /// @param level Minimal severity level
    void set_min_severity( custom_severity_level level );

    /// @brief Change the logging sink type.
    /// @param sink_type Type of the sink ("console", "file", "syslog", "null")
    /// @param dir Optional parameter for the directory used for the file sink
    void change_sink( const std::string& sink_type,
                      const std::string& dir = "" );

    /// @brief Set the format type.
    /// @param format_type Format type (Text or HTML)
    void set_format_type( FormatType format_type );

    /// @brief Get the current debug level
    /// @return Current debug level
    int get_debug_level() const { return debug_level_; }

    /// @brief Get the channel name
    /// @return Channel name
    const std::string& get_channel() const { return channel_name_; }

    /// @brief Add a sink with severity filtering
    /// @param sink The sink to add
    /// @param min_severity Minimum severity for this sink
    /// @param max_severity Maximum severity for this sink (optional)
    void add_filtered_sink(boost::shared_ptr< boost::log::sinks::sink > sink,
                          custom_severity_level min_severity,
                          custom_severity_level max_severity = custom_severity_level(severity_level::phone));

    /// @brief Setup optimized routing (debug to cerr, others to cout/file)
    void setup_optimized_routing();

    /// @brief Create a console sink for stderr
    boost::shared_ptr< boost::log::sinks::sink > create_cerr_sink();

    /// @brief Create a console sink for stdout
    boost::shared_ptr< boost::log::sinks::sink > create_cout_sink();

    /// @brief Set a custom sink for this logger (for dependency injection)
    /// @param sink Custom sink to use instead of default
    /// @note This is used by LoggerManager for dependency injection patterns
    void set_custom_sink(boost::shared_ptr<boost::log::sinks::sink> sink);
    
    /// @brief Set a global custom sink that will be used by ALL SimpleLogger instances
    /// @param sink Custom sink to use globally, or nullptr to clear global override
    /// @note This affects all existing and future SimpleLogger instances
    static void set_global_custom_sink(boost::shared_ptr<boost::log::sinks::sink> sink);


    friend std::ostream& operator<<( std::ostream&                os,
                                     const custom_severity_level& level );

private:
    /// @brief Internal version of create_console_sink for first-time initialization
    boost::shared_ptr< boost::log::sinks::sink > create_console_sink_internal();
    
    /// @brief Flag to track if global sink has been initialized
    static bool global_sink_initialized_;
    
    /// @brief Mutex for thread-safe global sink initialization
    static std::mutex global_sink_mutex_;
    
    
    std::string channel_name_;
    boost::log::sources::severity_channel_logger_mt< custom_severity_level, std::string > channel_logger_;
    boost::log::sources::severity_logger_mt< custom_severity_level > logger;
    std::mutex                                                       mutex_;
    FormatType                                   format_type_;
    int                                          debug_level_;
    custom_severity_level                        min_severity_;
    std::vector<boost::shared_ptr< boost::log::sinks::sink >> sinks_;
    boost::shared_ptr< boost::log::sinks::sink > current_sink_;
    std::string                                  log_directory_;

    void init_logging( boost::shared_ptr< boost::log::sinks::sink > sink );
    void init_common_attributes( );
    boost::shared_ptr< boost::log::sinks::sink > create_console_sink( );
    boost::shared_ptr< boost::log::sinks::sink >
    create_rotating_file_sink( const std::string& dir );

    boost::shared_ptr< boost::log::sinks::sink > create_syslog_sink( );

    boost::shared_ptr< boost::log::sinks::sink > create_null_sink( );

    void
    apply_formatter( boost::shared_ptr< boost::log::sinks::synchronous_sink<
                         boost::log::sinks::text_ostream_backend > >& sink );

    void
    apply_formatter( boost::shared_ptr< boost::log::sinks::synchronous_sink<
                         boost::log::sinks::text_file_backend > >& sink );

    void
    apply_formatter( boost::shared_ptr< boost::log::sinks::synchronous_sink<
                         boost::log::sinks::syslog_backend > >& sink );

    std::string timestamp_str( ) const;
};

#include "SimpleLogger.inl"

#endif // SIMPLE_LOGGER_HH
