#![allow(
    clippy::assertions_on_constants,
    clippy::assertions_on_result_states,
    clippy::clone_on_copy,
    clippy::decimal_literal_representation,
    clippy::doc_markdown,
    clippy::empty_line_after_doc_comments,
    clippy::field_reassign_with_default,
    clippy::get_unwrap,
    clippy::identity_op,
    clippy::inconsistent_digit_grouping,
    clippy::indexing_slicing,
    clippy::integer_division,
    clippy::len_zero,
    clippy::let_underscore_must_use,
    clippy::manual_div_ceil,
    clippy::manual_let_else,
    clippy::manual_range_contains,
    clippy::modulo_arithmetic,
    clippy::needless_range_loop,
    clippy::non_ascii_literal,
    clippy::redundant_clone,
    clippy::shadow_reuse,
    clippy::shadow_same,
    clippy::shadow_unrelated,
    clippy::single_match_else,
    clippy::str_to_string,
    clippy::string_slice,
    clippy::tests_outside_test_module,
    clippy::too_many_lines,
    clippy::unnecessary_wraps,
    clippy::unseparated_literal_suffix,
    clippy::use_debug,
    clippy::useless_vec,
    clippy::wildcard_enum_match_arm,
    clippy::else_if_without_else,
    clippy::expect_used,
    clippy::missing_const_for_fn,
    clippy::similar_names,
    clippy::type_complexity,
    clippy::collapsible_else_if,
    clippy::doc_lazy_continuation,
    clippy::items_after_test_module,
    clippy::map_clone,
    clippy::multiple_unsafe_ops_per_block,
    clippy::unwrap_or_default,
    clippy::assign_op_pattern,
    clippy::needless_borrow,
    clippy::println_empty_string,
    clippy::unnecessary_cast,
    clippy::used_underscore_binding,
    clippy::create_dir,
    clippy::implicit_saturating_sub,
    clippy::exit,
    clippy::expect_fun_call,
    clippy::too_many_arguments,
    clippy::unnecessary_map_or,
    clippy::unwrap_used,
    dead_code,
    unused_imports,
    unused_variables,
    clippy::cloned_ref_to_slice_refs,
    clippy::neg_multiply,
    clippy::while_let_loop,
    clippy::bool_assert_comparison,
    clippy::excessive_precision,
    clippy::trivially_copy_pass_by_ref,
    clippy::op_ref,
    clippy::redundant_closure,
    clippy::unnecessary_lazy_evaluations,
    clippy::if_then_some_else_none,
    clippy::unnecessary_to_owned,
    clippy::single_component_path_imports,
)]
//! WAVE 26 P1: Integration tests for advanced DQN features
//!
//! Tests for:
//! - P1.3: Sharpe ratio reward component
//! - P1.6: Adaptive dropout scheduling
//! - P1.7: Hindsight Experience Replay (HER)
//! - P1.8: Curiosity-driven exploration (tested in curiosity module)
//! - P1.9: Generalized Advantage Estimation (GAE)
//! - P1.11: Noisy network sigma scheduling

use ml::trainers::dqn::{DQNHyperparameters, DQNTrainer};

#[test]
fn test_p1_features_initialization() {
    // Test that all P1 features can be initialized correctly
    let mut hyperparams = DQNHyperparameters::conservative();

    // Enable all P1 features
    hyperparams.sharpe_weight = 0.3;
    hyperparams.sharpe_window = 20;
    hyperparams.enable_dropout_scheduler = true;
    hyperparams.dropout_initial = 0.5;
    hyperparams.dropout_final = 0.1;
    hyperparams.dropout_anneal_steps = 10000;
    hyperparams.her_ratio = 0.5;
    hyperparams.her_strategy = "future".to_string();
    hyperparams.curiosity_weight = 0.1;
    hyperparams.enable_gae = true;
    hyperparams.gae_lambda = 0.95;
    hyperparams.enable_noisy_sigma_scheduler = true;
    hyperparams.noisy_sigma_initial = 0.6;
    hyperparams.noisy_sigma_final = 0.4;
    hyperparams.noisy_sigma_anneal_steps = 10000;

    // Create trainer (should not panic)
    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Failed to create DQNTrainer with P1 features: {:?}", result.err());
}

#[test]
fn test_p1_3_sharpe_reward_disabled_by_default() {
    // Test that Sharpe reward is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.sharpe_weight, 0.0, "Sharpe weight should be 0.0 by default");
    assert_eq!(hyperparams.sharpe_window, 20, "Sharpe window should be 20 by default");
}

#[test]
fn test_p1_6_dropout_scheduler_disabled_by_default() {
    // Test that dropout scheduler is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.enable_dropout_scheduler, false, "Dropout scheduler should be disabled by default");
}

#[test]
fn test_p1_7_her_disabled_by_default() {
    // Test that HER is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.her_ratio, 0.0, "HER ratio should be 0.0 by default");
    assert_eq!(hyperparams.her_strategy, "future", "HER strategy should be 'future' by default");
}

#[test]
fn test_p1_8_curiosity_disabled_by_default() {
    // Test that curiosity is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.curiosity_weight, 0.0, "Curiosity weight should be 0.0 by default");
}

#[test]
fn test_p1_9_gae_disabled_by_default() {
    // Test that GAE is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.enable_gae, false, "GAE should be disabled by default");
    assert_eq!(hyperparams.gae_lambda, 0.95, "GAE lambda should be 0.95 by default");
}

#[test]
fn test_p1_11_noisy_sigma_scheduler_disabled_by_default() {
    // Test that noisy sigma scheduler is disabled by default
    let hyperparams = DQNHyperparameters::conservative();
    assert_eq!(hyperparams.enable_noisy_sigma_scheduler, false, "Noisy sigma scheduler should be disabled by default");
}

#[test]
fn test_p1_features_with_partial_enablement() {
    // Test that we can selectively enable P1 features
    let mut hyperparams = DQNHyperparameters::conservative();

    // Enable only Sharpe reward and GAE
    hyperparams.sharpe_weight = 0.4;
    hyperparams.enable_gae = true;

    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Failed to create DQNTrainer with partial P1 features: {:?}", result.err());
}

#[test]
fn test_p1_her_strategy_validation() {
    // Test that HER strategy defaults to "future" for invalid values
    let mut hyperparams = DQNHyperparameters::conservative();
    hyperparams.her_ratio = 0.5;
    hyperparams.her_strategy = "invalid_strategy".to_string();

    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Should default to 'future' strategy for invalid HER strategy");
}

#[test]
fn test_p1_sharpe_weight_bounds() {
    // Test that Sharpe weight can be set to various valid values
    let test_weights = vec![0.0, 0.1, 0.3, 0.5, 1.0];

    for weight in test_weights {
        let mut hyperparams = DQNHyperparameters::conservative();
        hyperparams.sharpe_weight = weight;

        let result = DQNTrainer::new(hyperparams);
        assert!(result.is_ok(), "Failed to create DQNTrainer with sharpe_weight={}: {:?}", weight, result.err());
    }
}

#[test]
fn test_p1_her_ratio_bounds() {
    // Test that HER ratio can be set to various valid values
    let test_ratios = vec![0.0, 0.3, 0.5, 0.8, 1.0];

    for ratio in test_ratios {
        let mut hyperparams = DQNHyperparameters::conservative();
        hyperparams.her_ratio = ratio;

        let result = DQNTrainer::new(hyperparams);
        assert!(result.is_ok(), "Failed to create DQNTrainer with her_ratio={}: {:?}", ratio, result.err());
    }
}

#[test]
fn test_p1_gae_lambda_bounds() {
    // Test that GAE lambda can be set to various valid values
    let test_lambdas = vec![0.9, 0.95, 0.98, 0.99];

    for lambda in test_lambdas {
        let mut hyperparams = DQNHyperparameters::conservative();
        hyperparams.enable_gae = true;
        hyperparams.gae_lambda = lambda;

        let result = DQNTrainer::new(hyperparams);
        assert!(result.is_ok(), "Failed to create DQNTrainer with gae_lambda={}: {:?}", lambda, result.err());
    }
}

#[test]
fn test_p1_dropout_scheduler_parameters() {
    // Test that dropout scheduler parameters are validated
    let mut hyperparams = DQNHyperparameters::conservative();
    hyperparams.enable_dropout_scheduler = true;
    hyperparams.dropout_initial = 0.5;
    hyperparams.dropout_final = 0.1;
    hyperparams.dropout_anneal_steps = 10000;

    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Failed to create DQNTrainer with dropout scheduler: {:?}", result.err());
}

#[test]
fn test_p1_noisy_sigma_scheduler_parameters() {
    // Test that noisy sigma scheduler parameters are validated
    let mut hyperparams = DQNHyperparameters::conservative();
    hyperparams.enable_noisy_sigma_scheduler = true;
    hyperparams.noisy_sigma_initial = 0.6;
    hyperparams.noisy_sigma_final = 0.4;
    hyperparams.noisy_sigma_anneal_steps = 10000;

    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Failed to create DQNTrainer with noisy sigma scheduler: {:?}", result.err());
}

#[test]
fn test_p1_all_features_enabled_max_configuration() {
    // Test maximum configuration with all P1 features enabled at high values
    let mut hyperparams = DQNHyperparameters::conservative();

    // Max P1 configuration
    hyperparams.sharpe_weight = 0.5;
    hyperparams.sharpe_window = 50;
    hyperparams.enable_dropout_scheduler = true;
    hyperparams.dropout_initial = 0.7;
    hyperparams.dropout_final = 0.05;
    hyperparams.dropout_anneal_steps = 20000;
    hyperparams.her_ratio = 0.8;
    hyperparams.her_strategy = "final".to_string();
    hyperparams.curiosity_weight = 0.5;
    hyperparams.enable_gae = true;
    hyperparams.gae_lambda = 0.99;
    hyperparams.enable_noisy_sigma_scheduler = true;
    hyperparams.noisy_sigma_initial = 0.8;
    hyperparams.noisy_sigma_final = 0.2;
    hyperparams.noisy_sigma_anneal_steps = 20000;

    let result = DQNTrainer::new(hyperparams);
    assert!(result.is_ok(), "Failed to create DQNTrainer with max P1 configuration: {:?}", result.err());
}
