//
// LDASTools frameCPP - frameCPP-Specific Debug Level Manager Wrapper
//
// Copyright (C) 2025 California Institute of Technology
//
// LDASTools frameCPP is free software; you may redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 (GPLv2) of the
// License or at your discretion, any later version.
//

#ifndef FRAMECPP_UTILITIES_FRAMECPP_DEBUG_MANAGER_HH
#define FRAMECPP_UTILITIES_FRAMECPP_DEBUG_MANAGER_HH

#include "ldastoolsal/DebugLevelManager.hh"
#include "ldastoolsal/CommandLineOptions.hh"
#include "ldastoolsal/Logger.hh"

// Forward declarations to avoid circular dependencies
namespace LDASTools { namespace AL { class LoggerManager; }}
namespace FrameCPP { namespace Common { struct FrameCPPServices; }}

namespace FrameCPP {
namespace Utilities {

/**
 * @brief frameCPP-specific debug level manager
 * 
 * This class extends the generic ldastoolsal DebugLevelManager with
 * frameCPP-specific configuration (environment variables and channel examples).
 * All other functionality is inherited directly from the base class.
 * 
 * @example Basic Usage
 * @code
 * // In main() of frameCPP utility
 * if (!FrameCPPDebugManager::initialize(argc, argv, "framecpp_utility")) {
 *     return 0; // Help was shown
 * }
 * 
 * // Use inherited methods directly
 * FrameCPPDebugManager::set_global_level(20);
 * FrameCPPDebugManager::set_channel_level("framecpp.frtoc.*", 25);
 * 
 * // Library code remains unchanged
 * logger_log_debug(logger(), 25, "Debug message");
 * @endcode
 */
class FrameCPPDebugManager : public LDASTools::AL::DebugLevelManager {
public:
    /**
     * @brief Initialize debug level manager with frameCPP-specific configuration
     * @param argc Argument count from main()
     * @param argv Argument vector from main()
     * @param program_name Program name for help text
     * @return true if initialization successful, false if help was requested
     */
    static bool initialize(int argc, char* argv[], 
                          const std::string& program_name = "framecpp_utility") {
        // Register frameCPP-specific callbacks before initialization
        set_help_callback(get_available_channels_help);
        set_library_name("framecpp");
        set_env_prefix("FRAMECPP_DEBUG");
        set_example_channels({
            "framecpp.frtoc.*",
            "framecpp.frendoffile", 
            "framecpp.*"
        });
        
        // Initialize with frameCPP environment prefix
        bool result = LDASTools::AL::DebugLevelManager::initialize(
            argc, argv, program_name, "FRAMECPP_DEBUG");
            
        // Sync any cached loggers that were created before initialization
        if (result) {
            sync_all_cached_loggers();
        }
        return result;
    }
    
    /**
     * @brief Get formatted text showing available debug channels
     * @return String containing available channels organized by category
     * 
     * This method is used as a callback by the base class to provide
     * frameCPP-specific channel information in debug help output.
     */
    static std::string get_available_channels_help();
    
    /**
     * @brief Initialize debug system with services-based logging (Muldoon pattern)
     * 
     * This is the preferred initialization method that creates a complete
     * services context following Muldoon's dependency injection principles.
     * This method eliminates global static state and provides explicit 
     * service lifetime management.
     * 
     * @param argc Argument count from main()
     * @param argv Argument vector from main()
     * @param services Reference to services context that will be populated
     * @param program_name Program name for help text
     * @return true if initialization successful, false if help was requested
     * 
     * @example
     * @code
     * int main(int argc, char* argv[]) {
     *     auto logger_mgr = std::make_unique<LDASTools::AL::LoggerManager>();
     *     FrameCPPServices services(*logger_mgr);
     *     
     *     if (!FrameCPPDebugManager::initialize_with_services(argc, argv, services, "my_app")) {
     *         return 0; // Help was shown
     *     }
     *     
     *     // Use services throughout application
     *     SomeClass obj(services);
     *     obj.doWork();
     *     
     *     // Explicit cleanup before main() returns
     *     logger_mgr->shutdown();
     *     return 0;
     * }
     * @endcode
     */
    static bool initialize_with_services(int argc, char* argv[], 
                                        Common::FrameCPPServices& services,
                                        const std::string& program_name = "framecpp_utility");
    
    /**
     * @brief Sync services logger manager with current debug levels
     * 
     * This should be called after debug levels are changed to ensure
     * all cached loggers in the LoggerManager are updated.
     * 
     * @param services Services context containing logger manager to sync
     */
    static void sync_services_loggers(Common::FrameCPPServices& services);
    
    // All other methods inherited automatically from LDASTools::AL::DebugLevelManager:
    // - add_debug_options()         (boost::program_options integration)
    // - configure_from_options()    (automatic help handling with callbacks)
    // - set_global_level()
    // - set_channel_level()  
    // - parse_channel_spec()
    // - get_channel_level()
    // - should_log()
    // - get_global_level()
    // - load_from_environment()
    // - load_from_file()
    // - clear_channel_configs()
    // - get_channel_configs()
    // - print_configuration()
    // - validate_level()
    // - get_help_text() (enhanced with callback)
    
    /// @brief Get global debug level safely during static destruction
    /// @return Global debug level (cached value, safe during static cleanup)
    static int get_safe_global_level();
    
    /// @brief Set global level and cache it for safe static destruction access
    /// @param level Debug level to set
    static void set_global_level_with_cache(int level);

private:
    static int cached_global_level_;  // Safe storage for static destruction
    
    // Private constructor - all methods are static
    FrameCPPDebugManager() = delete;
};

// Convenience alias for backwards compatibility
using DebugLevelManager = FrameCPPDebugManager;

} // namespace Utilities
} // namespace FrameCPP

#endif // FRAMECPP_UTILITIES_FRAMECPP_DEBUG_MANAGER_HH