//! Comprehensive Interactive Brokers TWS/Gateway Integration Tests
//!
//! Tests broker connectivity, order management, execution reporting,
//! error recovery, and edge cases for Interactive Brokers integration.

#![allow(
    clippy::absurd_extreme_comparisons,
    clippy::assertions_on_constants,
    clippy::assertions_on_result_states,
    clippy::clone_on_copy,
    clippy::decimal_literal_representation,
    clippy::doc_lazy_continuation,
    clippy::doc_markdown,
    clippy::double_comparisons,
    clippy::else_if_without_else,
    clippy::empty_drop,
    clippy::expect_used,
    clippy::field_reassign_with_default,
    clippy::format_push_string,
    clippy::if_then_some_else_none,
    clippy::indexing_slicing,
    clippy::integer_division,
    clippy::len_zero,
    clippy::let_and_return,
    clippy::let_underscore_must_use,
    clippy::manual_let_else,
    clippy::manual_range_contains,
    clippy::map_err_ignore,
    clippy::missing_const_for_fn,
    clippy::modulo_arithmetic,
    clippy::needless_range_loop,
    clippy::new_without_default,
    clippy::non_ascii_literal,
    clippy::nonminimal_bool,
    clippy::octal_escapes,
    clippy::overly_complex_bool_expr,
    clippy::redundant_clone,
    clippy::shadow_reuse,
    clippy::shadow_unrelated,
    clippy::similar_names,
    clippy::single_component_path_imports,
    clippy::single_match_else,
    clippy::str_to_string,
    clippy::string_slice,
    clippy::tests_outside_test_module,
    clippy::unnecessary_cast,
    clippy::unnecessary_get_then_check,
    clippy::unnecessary_unwrap,
    clippy::unseparated_literal_suffix,
    clippy::unwrap_or_default,
    clippy::unwrap_used,
    clippy::use_debug,
    clippy::useless_vec,
    clippy::wildcard_enum_match_arm,
    dead_code,
    deprecated,
    unreachable_pub,
    unused_assignments,
    unused_comparisons,
    unused_imports,
    unused_variables
)]

use chrono::Utc;
use common::{OrderId, OrderSide, OrderStatus, OrderType, Position, Symbol, TimeInForce};
use data::brokers::common::{BrokerConnectionStatus, BrokerError, ExecutionReport, TradingOrder};
use data::brokers::interactive_brokers::IBConfig;
// Note: IBClient doesn't exist - InteractiveBrokersAdapter is the actual implementation
// use data::brokers::interactive_brokers::{IBClient, IBConfig};
use num_traits::ToPrimitive;
use rust_decimal::Decimal;
use std::str::FromStr;
use uuid::Uuid;

mod test_helpers;

// ============================================================================
// IBConfig Tests - Configuration Validation
// ============================================================================

#[test]
fn test_ib_config_default_values() {
    let config = IBConfig::default();

    // Verify default configuration (respects environment variables)
    assert_eq!(config.host, test_helpers::expected_host());
    assert_eq!(config.port, test_helpers::expected_port());
    assert!(config.connection_timeout > 0);
    assert!(config.heartbeat_interval > 0);
    assert!(config.request_timeout > 0);
}

#[test]
fn test_ib_config_paper_trading() {
    let config = test_helpers::test_ib_config_paper();

    assert_eq!(config.port, test_helpers::expected_port());
    assert!(config.account_id.starts_with("DU") || config.account_id.starts_with("U"));
}

#[test]
fn test_ib_config_live_trading() {
    let config = test_helpers::test_ib_config_live();

    assert_eq!(config.port, 7496);
    assert!(config.account_id.starts_with("U"));
}

#[test]
fn test_ib_config_gateway() {
    let config = test_helpers::test_ib_config_gateway();

    assert_eq!(config.port, 4001);
}

#[test]
fn test_ib_config_client_id_validation() {
    // Test valid client ID range (0-32767)
    let valid_ids = vec![0, 1, 100, 1000, 32767];

    for id in valid_ids {
        let config = IBConfig {
            client_id: id,
            ..IBConfig::default()
        };
        assert!(config.client_id >= 0 && config.client_id <= 32767);
    }
}

#[test]
fn test_ib_config_timeout_edge_cases() {
    let config = IBConfig {
        connection_timeout: 0,
        heartbeat_interval: 0,
        request_timeout: 0,
        ..IBConfig::default()
    };

    // Should handle zero timeouts gracefully
    assert_eq!(config.connection_timeout, 0);
}

#[test]
fn test_ib_config_serialization() {
    use serde_json;

    let config = IBConfig::default();
    let json = serde_json::to_string(&config).unwrap();
    let deserialized: IBConfig = serde_json::from_str(&json).unwrap();

    assert_eq!(config.host, deserialized.host);
    assert_eq!(config.port, deserialized.port);
    assert_eq!(config.client_id, deserialized.client_id);
}

// ============================================================================
// TradingOrder Tests - Order Construction and Validation
// ============================================================================

#[test]
fn test_trading_order_market_order() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Market,
        quantity: 100.0,
        price: None,
        stop_price: None,
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    assert_eq!(order.symbol, "AAPL".to_string());
    assert!(matches!(order.side, OrderSide::Buy));
    assert!(matches!(order.order_type, OrderType::Market));
    assert!(order.price.is_none());
}

#[test]
fn test_trading_order_limit_order() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "TSLA".to_string(),
        side: OrderSide::Sell,
        order_type: OrderType::Limit,
        quantity: 50.0,
        price: Some(250.50),
        stop_price: None,
        time_in_force: TimeInForce::GoodTillCancel,
        client_order_id: Some("DU123456".to_string()),
    };

    assert_eq!(order.symbol, "TSLA".to_string());
    assert!(matches!(order.side, OrderSide::Sell));
    assert!(matches!(order.order_type, OrderType::Limit));
    assert!(order.price.is_some());
}

#[test]
fn test_trading_order_stop_order() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "GOOGL".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Stop,
        quantity: 10.0,
        price: None,
        stop_price: Some(150.00),
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    assert!(matches!(order.order_type, OrderType::Stop));
    assert!(order.stop_price.is_some());
}

#[test]
fn test_trading_order_time_in_force_variants() {
    let tif_variants = vec![
        TimeInForce::Day,
        TimeInForce::GoodTillCancel,
        TimeInForce::ImmediateOrCancel,
        TimeInForce::FillOrKill,
    ];

    for tif in tif_variants {
        let order = TradingOrder {
            order_id: OrderId::new().to_string(),
            symbol: "SPY".to_string(),
            side: OrderSide::Buy,
            order_type: OrderType::Market,
            quantity: 1.0,
            price: None,
            stop_price: None,
            time_in_force: tif,
            client_order_id: Some("DU123456".to_string()),
        };

        assert!(!order.symbol.is_empty());
    }
}

#[test]
fn test_trading_order_quantity_edge_cases() {
    let quantities = vec![1.0, 0.01, 1000000.0];

    for qty in quantities {
        let order = TradingOrder {
            order_id: OrderId::new().to_string(),
            symbol: "BTC".to_string(),
            side: OrderSide::Buy,
            order_type: OrderType::Market,
            quantity: qty,
            price: None,
            stop_price: None,
            time_in_force: TimeInForce::Day,
            client_order_id: Some("DU123456".to_string()),
        };

        assert!(order.quantity > 0.0);
    }
}

// ============================================================================
// ExecutionReport Tests - Trade Execution Reporting
// ============================================================================

#[test]
fn test_execution_report_filled() {
    let report = ExecutionReport {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 150.25,
        executed_quantity: 100.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 1.50,
        fee: 0.02,
        status: OrderStatus::Filled,
    };

    assert!(matches!(report.status, OrderStatus::Filled));
    assert_eq!(report.executed_quantity, 100.0);
}

#[test]
fn test_execution_report_partial_fill() {
    let report = ExecutionReport {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 150.25,
        executed_quantity: 50.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 0.75,
        fee: 0.01,
        status: OrderStatus::PartiallyFilled,
    };

    assert!(matches!(report.status, OrderStatus::PartiallyFilled));
    assert!(report.executed_quantity < 100.0);
}

#[test]
fn test_execution_report_rejected() {
    let report = ExecutionReport {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 0.0,
        executed_quantity: 0.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 0.0,
        fee: 0.0,
        status: OrderStatus::Rejected,
    };

    assert!(matches!(report.status, OrderStatus::Rejected));
    assert_eq!(report.executed_quantity, 0.0);
}

#[test]
fn test_execution_report_cancelled() {
    let report = ExecutionReport {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 0.0,
        executed_quantity: 0.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 0.0,
        fee: 0.0,
        status: OrderStatus::Cancelled,
    };

    assert!(matches!(report.status, OrderStatus::Cancelled));
}

#[test]
fn test_execution_report_commission_edge_cases() {
    let commissions = vec![0.0, 0.01, 1.00, 100.00];

    for commission in commissions {
        let report = ExecutionReport {
            order_id: OrderId::new().to_string(),
            symbol: "AAPL".to_string(),
            side: OrderSide::Buy,
            executed_price: 150.25,
            executed_quantity: 100.0,
            timestamp_ns: std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap()
                .as_nanos() as u64,
            broker_id: "IB123456".to_string(),
            commission,
            fee: 0.02,
            status: OrderStatus::Filled,
        };

        assert!(matches!(report.status, OrderStatus::Filled));
    }
}

// ============================================================================
// BrokerConnectionStatus Tests - Connection State Management
// ============================================================================

#[test]
fn test_broker_connection_status_variants() {
    let statuses = vec![
        BrokerConnectionStatus::Disconnected,
        BrokerConnectionStatus::Connecting,
        BrokerConnectionStatus::Connected,
        BrokerConnectionStatus::Reconnecting,
        BrokerConnectionStatus::Error("Connection failed".to_string()),
    ];

    for status in statuses {
        let debug_str = format!("{:?}", status);
        assert!(!debug_str.is_empty());
    }
}

#[test]
fn test_broker_connection_status_transitions() {
    let mut status = BrokerConnectionStatus::Disconnected;

    // Simulate state transitions
    status = BrokerConnectionStatus::Connecting;
    assert!(matches!(status, BrokerConnectionStatus::Connecting));

    status = BrokerConnectionStatus::Connected;
    assert!(matches!(status, BrokerConnectionStatus::Connected));

    status = BrokerConnectionStatus::Reconnecting;
    assert!(matches!(status, BrokerConnectionStatus::Reconnecting));

    status = BrokerConnectionStatus::Error("Timeout".to_string());
    assert!(matches!(status, BrokerConnectionStatus::Error(_)));

    status = BrokerConnectionStatus::Disconnected;
    assert!(matches!(status, BrokerConnectionStatus::Disconnected));
}

// ============================================================================
// BrokerError Tests - Error Handling
// ============================================================================

#[test]
fn test_broker_error_variants() {
    let errors = vec![
        BrokerError::ConnectionFailed("Timeout".to_string()),
        BrokerError::Authentication("Invalid credentials".to_string()),
        BrokerError::Order("Insufficient margin".to_string()),
        BrokerError::Order("Missing price".to_string()),
        BrokerError::MarketData("Symbol XYZ not found".to_string()),
        BrokerError::Timeout("Rate limit exceeded".to_string()),
        BrokerError::ProtocolError("Server error".to_string()),
    ];

    for error in errors {
        let debug_str = format!("{:?}", error);
        assert!(!debug_str.is_empty());
    }
}

#[test]
fn test_broker_error_display() {
    let error = BrokerError::Order("Test rejection".to_string());
    let display_str = format!("{}", error);
    assert!(display_str.contains("Test rejection") || !display_str.is_empty());
}

// ============================================================================
// Position Tests - Position Management
// ============================================================================

#[test]
fn test_position_long() {
    let position = Position {
        id: Uuid::new_v4(),
        symbol: Symbol::from("AAPL").to_string(),
        quantity: Decimal::from_str("100").unwrap(),
        avg_price: Decimal::from_str("150.00").unwrap(),
        avg_cost: Decimal::from_str("150.00").unwrap(),
        basis: Decimal::from_str("15000.00").unwrap(),
        average_price: Decimal::from_str("150.00").unwrap(),
        market_value: Decimal::from_str("15500.00").unwrap(),
        unrealized_pnl: Decimal::from_str("500.00").unwrap(),
        realized_pnl: Decimal::ZERO,
        created_at: Utc::now(),
        updated_at: Utc::now(),
        last_updated: Utc::now(),
        current_price: Some(Decimal::from_str("155.00").unwrap()),
        notional_value: Decimal::from_str("15500.00").unwrap(),
        margin_requirement: Decimal::ZERO,
    };

    assert!(position.quantity > Decimal::ZERO);
    assert!(position.unrealized_pnl > Decimal::ZERO);
}

#[test]
fn test_position_short() {
    let position = Position {
        id: Uuid::new_v4(),
        symbol: Symbol::from("TSLA").to_string(),
        quantity: Decimal::from_str("-50").unwrap(),
        avg_price: Decimal::from_str("250.00").unwrap(),
        avg_cost: Decimal::from_str("250.00").unwrap(),
        basis: Decimal::from_str("-12500.00").unwrap(),
        average_price: Decimal::from_str("250.00").unwrap(),
        market_value: Decimal::from_str("-12250.00").unwrap(),
        unrealized_pnl: Decimal::from_str("250.00").unwrap(),
        realized_pnl: Decimal::ZERO,
        created_at: Utc::now(),
        updated_at: Utc::now(),
        last_updated: Utc::now(),
        current_price: Some(Decimal::from_str("245.00").unwrap()),
        notional_value: Decimal::from_str("12250.00").unwrap(),
        margin_requirement: Decimal::ZERO,
    };

    assert!(position.quantity < Decimal::ZERO);
    assert!(position.unrealized_pnl > Decimal::ZERO);
}

#[test]
fn test_position_flat() {
    let position = Position {
        id: Uuid::new_v4(),
        symbol: Symbol::from("SPY").to_string(),
        quantity: Decimal::ZERO,
        avg_price: Decimal::ZERO,
        avg_cost: Decimal::ZERO,
        basis: Decimal::ZERO,
        average_price: Decimal::ZERO,
        market_value: Decimal::ZERO,
        unrealized_pnl: Decimal::ZERO,
        realized_pnl: Decimal::from_str("1000.00").unwrap(),
        created_at: Utc::now(),
        updated_at: Utc::now(),
        last_updated: Utc::now(),
        current_price: Some(Decimal::from_str("450.00").unwrap()),
        notional_value: Decimal::ZERO,
        margin_requirement: Decimal::ZERO,
    };

    assert_eq!(position.quantity, Decimal::ZERO);
    assert_eq!(position.unrealized_pnl, Decimal::ZERO);
}

// ============================================================================
// Error Recovery Tests
// ============================================================================

#[test]
fn test_reconnection_backoff_strategy() {
    let base_delay_ms = 1000;
    let max_attempts = 5;

    for attempt in 0..max_attempts {
        let delay = base_delay_ms * 2_u64.pow(attempt);
        let capped_delay = delay.min(30_000); // Cap at 30 seconds

        assert!(capped_delay >= base_delay_ms);
        assert!(capped_delay <= 30_000);
    }
}

#[test]
fn test_max_reconnect_attempts_enforcement() {
    let config = IBConfig {
        max_reconnect_attempts: 3,
        ..IBConfig::default()
    };

    let mut attempts = 0;
    loop {
        attempts += 1;
        if attempts > config.max_reconnect_attempts {
            break;
        }
    }

    assert_eq!(attempts, config.max_reconnect_attempts + 1);
}

// ============================================================================
// Order Validation Tests
// ============================================================================

#[test]
fn test_order_validation_missing_price_for_limit() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Limit,
        quantity: 100.0,
        price: None, // Should have price
        stop_price: None,
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    // Limit orders require price
    assert!(order.price.is_none());
    assert!(matches!(order.order_type, OrderType::Limit));
}

#[test]
fn test_order_validation_zero_quantity() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Market,
        quantity: 0.0, // Invalid
        price: None,
        stop_price: None,
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    assert_eq!(order.quantity, 0.0);
}

#[test]
fn test_order_validation_empty_symbol() {
    let order = TradingOrder {
        order_id: OrderId::new().to_string(),
        symbol: "".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Market,
        quantity: 100.0,
        price: None,
        stop_price: None,
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    assert!(order.symbol.is_empty());
}

// ============================================================================
// Message Protocol Tests
// ============================================================================

#[test]
fn test_tws_message_encoding() {
    // Test TWS message field encoding
    let fields = vec!["1", "AAPL", "BUY", "100", "MKT"];

    let encoded = fields.join("\0");
    assert!(encoded.contains("AAPL"));
    assert!(encoded.contains("BUY"));
}

#[test]
fn test_tws_message_decoding() {
    // Test TWS message field decoding
    let message = "8\01\0AAPL\0100\0150.25\0";
    let fields: Vec<&str> = message.split('\0').collect();

    assert!(fields.len() > 0);
    assert!(fields.contains(&"AAPL"));
}

// ============================================================================
// Concurrent Operations Tests
// ============================================================================

#[tokio::test]
async fn test_concurrent_order_submissions() {
    use tokio::task;

    let handles: Vec<_> = (0..10)
        .map(|i| {
            task::spawn(async move {
                let order = TradingOrder {
                    order_id: OrderId::new().to_string(),
                    symbol: "AAPL".to_string(),
                    side: OrderSide::Buy,
                    order_type: OrderType::Market,
                    quantity: (i + 1) as f64,
                    price: None,
                    stop_price: None,
                    time_in_force: TimeInForce::Day,
                    client_order_id: Some("DU123456".to_string()),
                };
                order
            })
        })
        .collect();

    for handle in handles {
        let order = handle.await.unwrap();
        assert!(order.quantity > 0.0);
    }
}

// ============================================================================
// Integration Scenario Tests
// ============================================================================

#[test]
fn test_order_lifecycle_scenario() {
    // Simulate complete order lifecycle
    let order_id = OrderId::new();

    // 1. Order created
    let order = TradingOrder {
        order_id: order_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        order_type: OrderType::Limit,
        quantity: 100.0,
        price: Some(150.00),
        stop_price: None,
        time_in_force: TimeInForce::Day,
        client_order_id: Some("DU123456".to_string()),
    };

    assert!(matches!(order.order_type, OrderType::Limit));

    // 2. Order acknowledged (pending status)
    let ack_report = ExecutionReport {
        order_id: order_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 0.0,
        executed_quantity: 0.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 0.0,
        fee: 0.0,
        status: OrderStatus::Pending,
    };

    assert!(matches!(ack_report.status, OrderStatus::Pending));

    // 3. Partial fill
    let partial_report = ExecutionReport {
        order_id: order_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 150.00,
        executed_quantity: 50.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 0.75,
        fee: 0.01,
        status: OrderStatus::PartiallyFilled,
    };

    assert!(matches!(
        partial_report.status,
        OrderStatus::PartiallyFilled
    ));

    // 4. Complete fill
    let fill_report = ExecutionReport {
        order_id: order_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy,
        executed_price: 150.00,
        executed_quantity: 100.0,
        timestamp_ns: std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64,
        broker_id: "IB123456".to_string(),
        commission: 1.50,
        fee: 0.02,
        status: OrderStatus::Filled,
    };

    assert!(matches!(fill_report.status, OrderStatus::Filled));
    assert_eq!(
        fill_report.executed_quantity,
        order.quantity.to_f64().unwrap_or(0.0)
    );
}
