#![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,
)]
//! Test suite for configurable initial capital feature
//!
//! Validates that initial capital can be configured via CLI and properly
//! scales position sizes, portfolio values, and cash balances across
//! different account sizes ($1K to $1M+).

use ml::dqn::portfolio_tracker::PortfolioTracker;

/// Helper function to create a PortfolioTracker with specified capital
fn create_tracker_with_capital(capital: f32) -> PortfolioTracker {
    PortfolioTracker::new(
        capital,
        0.0001, // avg_spread: 1 basis point (standard)
        0.0,    // cash_reserve_percent: 0% (backward compatible, no reserve requirement)
    )
}

#[test]
fn test_small_capital_10k() {
    let capital = 10_000.0;
    let tracker = create_tracker_with_capital(capital);
    let price = 5_600.0; // Typical ES price

    // Calculate expected max position (capital / price)
    let expected_max_position = capital / price; // 1.78 contracts

    // Verify initialization
    assert_eq!(
        tracker.cash_balance(),
        capital,
        "Cash balance should equal initial capital"
    );
    assert_eq!(
        tracker.total_value(price),
        capital,
        "Portfolio value should equal initial capital before any trades"
    );
    assert_eq!(
        tracker.current_position(),
        0.0,
        "Position should be flat initially"
    );

    // Verify position scaling (approximate due to floating point)
    assert!(
        (expected_max_position - 1.78).abs() < 0.01,
        "Max position should be ~1.78 contracts for $10K at $5,600"
    );
}

#[test]
fn test_standard_capital_100k() {
    let capital = 100_000.0;
    let tracker = create_tracker_with_capital(capital);
    let price = 5_600.0;

    // Calculate expected max position
    let expected_max_position = capital / price; // 17.85 contracts

    // Verify initialization
    assert_eq!(tracker.cash_balance(), capital);
    assert_eq!(tracker.total_value(price), capital);
    assert_eq!(tracker.current_position(), 0.0);

    // Verify position scaling (baseline behavior)
    assert!(
        (expected_max_position - 17.85).abs() < 0.01,
        "Max position should be ~17.85 contracts for $100K at $5,600"
    );
}

#[test]
fn test_large_capital_500k() {
    let capital = 500_000.0;
    let tracker = create_tracker_with_capital(capital);
    let price = 5_600.0;

    // Calculate expected max position (5x standard)
    let expected_max_position = capital / price; // 89.28 contracts

    // Verify initialization
    assert_eq!(tracker.cash_balance(), capital);
    assert_eq!(tracker.total_value(price), capital);
    assert_eq!(tracker.current_position(), 0.0);

    // Verify linear scaling (5x capital = 5x positions)
    let standard_max = 100_000.0 / price;
    assert!(
        (expected_max_position / standard_max - 5.0).abs() < 0.01,
        "Position capacity should scale linearly with capital (5x)"
    );
}

#[test]
fn test_institutional_capital_1m() {
    let capital = 1_000_000.0;
    let tracker = create_tracker_with_capital(capital);
    let price = 5_600.0;

    // Calculate expected max position (10x standard)
    let expected_max_position = capital / price; // 178.57 contracts

    // Verify initialization
    assert_eq!(tracker.cash_balance(), capital);
    assert_eq!(tracker.total_value(price), capital);
    assert_eq!(tracker.current_position(), 0.0);

    // Verify linear scaling (10x capital = 10x positions)
    let standard_max = 100_000.0 / price;
    assert!(
        (expected_max_position / standard_max - 10.0).abs() < 0.01,
        "Position capacity should scale linearly with capital (10x)"
    );

    // Stress test: Verify large portfolio value calculations don't overflow
    let large_value = tracker.total_value(price);
    assert!(
        large_value.is_finite(),
        "Large portfolio values should not overflow"
    );
    assert!(large_value > 0.0, "Portfolio value should be positive");
}

#[test]
fn test_minimum_capital_1k() {
    let capital = 1_000.0;
    let tracker = create_tracker_with_capital(capital);
    let price = 5_600.0;

    // Calculate expected max position (very small)
    let expected_max_position = capital / price; // 0.178 contracts

    // Verify initialization
    assert_eq!(tracker.cash_balance(), capital);
    assert_eq!(tracker.total_value(price), capital);
    assert_eq!(tracker.current_position(), 0.0);

    // Verify fractional position handling
    assert!(
        expected_max_position < 1.0,
        "Minimum capital should result in fractional position capacity"
    );
    assert!(
        (expected_max_position - 0.178).abs() < 0.01,
        "Max position should be ~0.178 contracts for $1K at $5,600"
    );

    // Edge case: Verify position limits are enforced (MAX_POSITION_CONTRACTS=1.0)
    // This is enforced in execute_action(), not in max_position calculation
}

#[test]
fn test_portfolio_value_initialization() {
    let test_capitals = vec![1_000.0, 10_000.0, 100_000.0, 500_000.0, 1_000_000.0];

    for capital in test_capitals {
        let tracker = create_tracker_with_capital(capital);
        let price = 5_600.0;

        // Portfolio value should equal initial capital before any trades
        assert_eq!(
            tracker.total_value(price),
            capital,
            "Portfolio value should equal initial capital of ${:.0}",
            capital
        );

        // Normalized value should be 1.0 (portfolio_value / initial_capital)
        let raw_features = tracker.get_raw_portfolio_features(price);
        let portfolio_value = raw_features[0];
        assert_eq!(
            portfolio_value, capital,
            "Raw portfolio value should equal initial capital"
        );

        // Normalized features: [normalized_value, normalized_position, spread]
        let normalized_features = tracker.get_portfolio_features(price);
        let normalized_value = normalized_features[0];
        assert!(
            (normalized_value - 1.0).abs() < 0.0001,
            "Normalized portfolio value should be 1.0 (no P&L yet)"
        );
    }
}

#[test]
fn test_cash_balance_initialization() {
    let test_capitals = vec![1_000.0, 10_000.0, 100_000.0, 500_000.0, 1_000_000.0];

    for capital in test_capitals {
        let tracker = create_tracker_with_capital(capital);

        // Cash balance should equal initial capital
        assert_eq!(
            tracker.cash_balance(),
            capital,
            "Cash balance should equal initial capital of ${:.0}",
            capital
        );

        // After reset, cash should be restored to initial capital
        let mut tracker_mut = tracker.clone();
        tracker_mut.reset();
        assert_eq!(
            tracker_mut.cash_balance(),
            capital,
            "Cash balance should reset to initial capital of ${:.0}",
            capital
        );
    }
}

#[test]
fn test_position_scaling_accuracy() {
    // Test that position scaling formula (capital / price) is accurate
    let test_cases = vec![
        (1_000.0, 5_600.0, 0.178),     // $1K at $5,600 = 0.178 contracts
        (10_000.0, 5_600.0, 1.785),    // $10K at $5,600 = 1.785 contracts
        (100_000.0, 5_600.0, 17.857),  // $100K at $5,600 = 17.857 contracts
        (500_000.0, 5_600.0, 89.285),  // $500K at $5,600 = 89.285 contracts
        (1_000_000.0, 5_600.0, 178.571), // $1M at $5,600 = 178.571 contracts
    ];

    for (capital, price, expected_max) in test_cases {
        let tracker = create_tracker_with_capital(capital);
        let calculated_max = capital / price;

        assert!(
            (calculated_max - expected_max).abs() < 0.001,
            "Max position for ${:.0} at ${:.0} should be {:.3} contracts, got {:.3}",
            capital,
            price,
            expected_max,
            calculated_max
        );

        // Verify PortfolioTracker uses this formula internally
        let raw_features = tracker.get_raw_portfolio_features(price);
        let cash_balance = raw_features[0]; // Portfolio value = cash (no position)
        assert_eq!(cash_balance, capital, "Raw portfolio features should show correct cash balance");
    }
}
