#include "ldastoolsal/Logger.hh"
#include <iostream>
#include <thread>
#include <chrono>

// Declare channel-specific loggers
DECLARE_CHANNEL_LOGGER( framecpp, "framecpp" )
DECLARE_CHANNEL_LOGGER( framecpp_frtoc, "framecpp.frtoc" )
DECLARE_CHANNEL_LOGGER( framecpp_frvect, "framecpp.frvect" )
DECLARE_CHANNEL_LOGGER( ldas, "ldas" )
DECLARE_CHANNEL_LOGGER( ldas_cache, "ldas.cache" )

void
test_basic_logging( )
{
    std::cout << "\n=== Testing Basic Logging ===\n" << std::endl;

    auto* logger = default_logger( );

    logger_log_debug( logger, 5, "This is a debug message at level 5" );
    logger_log_ok( logger, "Operation completed successfully" );
    logger_log_note( logger, "This is an informational note" );
    logger_log_warning( logger, "Warning: ", 42, " items remaining" );
    logger_log_error_non_fatal( logger, "Non-fatal error occurred" );
    logger_log_error( logger, "Fatal error!" );
}

void
test_hierarchical_logging( )
{
    std::cout << "\n=== Testing Hierarchical Logging ===\n" << std::endl;

    // Get different channel loggers
    auto* framecpp = get_framecpp_logger( );
    auto* frtoc = get_framecpp_frtoc_logger( );
    auto* frvect = get_framecpp_frvect_logger( );

    // Log to different channels
    logger_log_note( framecpp, "Message from framecpp root" );
    logger_log_debug( frtoc, 5, "FrTOC processing data" );
    logger_log_debug( frvect, 3, "FrVect operation" );
}

void
test_group_configuration( )
{
    std::cout << "\n=== Testing Group Configuration ===\n" << std::endl;

    auto& registry = LDASTools::AL::LoggerRegistry::getInstance( );

    // Set debug level for all framecpp modules
    registry.set_group_debug_level( "framecpp.*", 5 );

    // Override for specific module
    registry.set_group_debug_level( "framecpp.frtoc", 10 );

    auto* frtoc = get_framecpp_frtoc_logger( );
    auto* frvect = get_framecpp_frvect_logger( );

    // These should show based on different debug levels
    logger_log_debug( frtoc, 8, "This shows (level 8 <= 10)" );
    logger_log_debug( frvect, 8, "This doesn't show (level 8 > 5)" );
    logger_log_debug( frvect, 4, "This shows (level 4 <= 5)" );
}

void
test_severity_routing( )
{
    std::cout << "\n=== Testing Severity-Based Routing ===\n" << std::endl;
    std::cout << "Note: Debug messages should go to stderr, others to stdout\n"
              << std::endl;

    auto* logger = default_logger( );

    // Setup optimized routing (debug -> cerr, others -> cout/file)
    logger->setup_optimized_routing( );

    // These go to different outputs
    logger_log_debug( logger, 5, "[STDERR] Debug message" );
    logger_log_ok( logger, "[STDOUT] OK message" );
    logger_log_warning( logger, "[STDOUT] Warning message" );
    logger_log_error( logger, "[STDERR] Error message (also logged to file)" );
}

void
test_lazy_evaluation( )
{
    std::cout << "\n=== Testing Lazy Evaluation ===\n" << std::endl;

    auto* logger = default_logger( );
    logger->set_debug_level( 3 ); // Set low threshold - shows messages 1-3 only

    // This expensive operation should NOT be evaluated
    auto expensive_operation = []( ) -> std::string {
        std::cout << "EXPENSIVE OPERATION CALLED - THIS SHOULD NOT APPEAR!"
                  << std::endl;
        std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
        return "expensive result";
    };

    // This demonstrates early exit optimization - the expensive operation
    // is NOT called because the debug level check happens first
    std::cout << "Testing level 5 message with threshold 3 (should be "
                 "filtered, no expensive call):"
              << std::endl;
    logger_log_debug( logger, 5, "Debug: this message filtered out" );

    // This should also be filtered without calling expensive operation
    auto start_time = std::chrono::steady_clock::now( );
    logger_log_debug( logger, 8, "Debug: ", "level 8 message also filtered" );
    auto end_time = std::chrono::steady_clock::now( );
    auto duration = std::chrono::duration_cast< std::chrono::milliseconds >(
        end_time - start_time );
    std::cout << "Filtered debug call took " << duration.count( )
              << "ms (should be ~0)" << std::endl;

    // Raise the threshold
    logger->set_debug_level( 10 );

    // Now this will evaluate since 5 <= 10
    std::cout << "Raised debug level to 10, next operation SHOULD execute:"
              << std::endl;
    logger_log_debug( logger, 5, "Debug: ", expensive_operation( ) );
}

void
test_scoped_verbosity( )
{
    std::cout << "\n=== Testing Scoped Channel Verbosity ===\n" << std::endl;

    auto* frtoc = get_framecpp_frtoc_logger( );
    frtoc->set_debug_level( 3 );

    logger_log_debug( frtoc, 5, "This won't show (level 5 > 3)" );

    {
        // Temporarily increase verbosity
        LDASTools::AL::ScopedChannelVerbosity verbose( "framecpp.frtoc", 10 );
        logger_log_debug(
            frtoc, 5, "This WILL show due to temporary verbosity" );
        logger_log_debug( frtoc, 8, "This also shows" );
    }

    logger_log_debug( frtoc, 5, "This won't show again (back to level 3)" );
}

void
test_pattern_matching( )
{
    std::cout << "\n=== Testing Pattern Matching ===\n" << std::endl;

    auto& registry = LDASTools::AL::LoggerRegistry::getInstance( );

    // Create various loggers
    get_channel_logger( "framecpp.frtoc.reader" );
    get_channel_logger( "framecpp.frtoc.writer" );
    get_channel_logger( "framecpp.frvect.processor" );
    get_channel_logger( "ldas.cache.manager" );

    // Configure using patterns
    registry.set_group_debug_level( "framecpp.frtoc.*", 8 );
    registry.set_group_debug_level( "*.processor", 10 );

    // Test the configuration
    auto* reader = get_channel_logger( "framecpp.frtoc.reader" );
    auto* processor = get_channel_logger( "framecpp.frvect.processor" );

    logger_log_debug( reader, 7, "Reader at level 7 (shows, <= 8)" );
    logger_log_debug( processor, 9, "Processor at level 9 (shows, <= 10)" );
}

void
test_multiple_sinks( )
{
    std::cout << "\n=== Testing Multiple Sinks ===\n" << std::endl;

    auto* logger = default_logger( );

    // Add filtered sinks for different severity ranges
    auto cerr_debug_sink = logger->create_cerr_sink( );
    logger->add_filtered_sink(
        cerr_debug_sink,
        SimpleLogger::custom_severity_level( 0 ), // Debug messages
        SimpleLogger::custom_severity_level( 10 ) );

    auto cout_info_sink = logger->create_cout_sink( );
    logger->add_filtered_sink(
        cout_info_sink,
        SimpleLogger::custom_severity_level( SimpleLogger::severity_level::ok ),
        SimpleLogger::custom_severity_level(
            SimpleLogger::severity_level::warning ) );

    // Test routing
    logger_log_debug( logger, 5, "[Should go to STDERR] Debug" );
    logger_log_note( logger, "[Should go to STDOUT] Note" );
}

int
main( int argc, char* argv[] )
{
    try
    {
        std::cout << "=== Hierarchical Logging System Test ===" << std::endl;
        std::cout
            << "Testing advanced logging features with group configuration,\n"
            << "lazy evaluation, and severity-based routing.\n"
            << std::endl;

        // Run all tests
        test_basic_logging( );
        test_hierarchical_logging( );
        test_group_configuration( );
        test_severity_routing( );
        test_lazy_evaluation( );
        test_scoped_verbosity( );
        test_pattern_matching( );
        test_multiple_sinks( );

        std::cout << "\n=== All Tests Complete ===" << std::endl;
        std::cout << "Check 'logs' directory for persistent error logs."
                  << std::endl;
    }
    catch ( const std::exception& e )
    {
        std::cerr << "Test failed with exception: " << e.what( ) << std::endl;
        return 1;
    }

    return 0;
}
