#![allow(
    clippy::tests_outside_test_module,
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::indexing_slicing,
    clippy::str_to_string,
    clippy::string_to_string,
    clippy::assertions_on_result_states,
    clippy::assertions_on_constants,
    clippy::let_underscore_must_use,
    clippy::use_debug,
    clippy::doc_markdown,
    clippy::shadow_unrelated,
    clippy::shadow_reuse,
    clippy::similar_names,
    clippy::clone_on_copy,
    clippy::get_unwrap,
    clippy::modulo_arithmetic,
    clippy::integer_division,
    clippy::non_ascii_literal,
    clippy::useless_vec,
    clippy::useless_format,
    clippy::wildcard_enum_match_arm,
    clippy::manual_range_contains,
    clippy::const_is_empty,
    clippy::needless_range_loop,
    clippy::field_reassign_with_default,
    clippy::items_after_test_module,
    clippy::missing_const_for_fn,
    unused_imports,
    unused_variables,
    unused_mut,
    unused_assignments,
    unused_comparisons,
    unused_must_use,
    dead_code,
)]
//! Trading Engine Core Tests
//!
//! Tests the core engine functionality that can be tested without broker integration
//! Focuses on: validation, account info, positions, subscriptions

use chrono::Utc;
use common::{MarketDataEvent, OrderSide, OrderType};
use rust_decimal::Decimal;
use std::sync::Arc;
use tokio::sync::broadcast;
use trading_engine::trading::data_interface::{DataProvider, Subscription};
use trading_engine::trading::engine::TradingEngine;

// ============================================================================
// Mock Data Provider
// ============================================================================

#[derive(Debug, Clone)]
struct MockDataProvider {
    market_data_tx: broadcast::Sender<MarketDataEvent>,
    order_update_tx: broadcast::Sender<MarketDataEvent>,
}

impl MockDataProvider {
    fn new() -> Self {
        let (market_data_tx, _) = broadcast::channel(1000);
        let (order_update_tx, _) = broadcast::channel(1000);
        Self {
            market_data_tx,
            order_update_tx,
        }
    }
}

#[async_trait::async_trait]
impl DataProvider for MockDataProvider {
    async fn subscribe_market_data(&self, _subscription: Subscription) -> Result<(), String> {
        Ok(())
    }

    fn subscribe_market_data_events(&self) -> broadcast::Receiver<MarketDataEvent> {
        self.market_data_tx.subscribe()
    }

    fn subscribe_order_update_events(&self) -> broadcast::Receiver<MarketDataEvent> {
        self.order_update_tx.subscribe()
    }
}

// ============================================================================
// Helpers
// ============================================================================

fn create_engine() -> TradingEngine {
    TradingEngine::new(Arc::new(MockDataProvider::new()))
}

// ============================================================================
// Engine Creation Tests
// ============================================================================

#[tokio::test]
async fn test_engine_creation() {
    let engine = create_engine();
    // Engine should be created successfully
    let stats = engine.get_trading_stats().await;
    assert_eq!(stats.total_orders, 0);
}

// ============================================================================
// Order Validation Tests - Test validation WITHOUT broker submission
// ============================================================================

#[tokio::test]
async fn test_validation_rejects_zero_quantity() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Market,
            Decimal::ZERO,
            None,
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("positive"));
}

#[tokio::test]
async fn test_validation_rejects_negative_quantity() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Market,
            Decimal::from(-10),
            None,
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("positive"));
}

#[tokio::test]
async fn test_validation_rejects_empty_symbol() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "".to_string(),
            OrderSide::Buy,
            OrderType::Market,
            Decimal::from(1),
            None,
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("symbol"));
}

#[tokio::test]
async fn test_validation_rejects_zero_limit_price() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(1),
            Some(Decimal::ZERO),
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("price"));
}

#[tokio::test]
async fn test_validation_rejects_negative_limit_price() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(1),
            Some(Decimal::from(-50000)),
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("price"));
}

#[tokio::test]
async fn test_validation_checks_buying_power() {
    let engine = create_engine();

    // Order that exceeds demo account buying power (100k)
    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(100), // 100 BTC
            Some(Decimal::from(50000)), // @ $50k = $5M total
            None,
        )
        .await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("buying power"));
}

#[tokio::test]
async fn test_validation_sell_order_no_buying_power_check() {
    let engine = create_engine();

    // Large sell order should pass validation (no buying power needed)
    // Will fail later at broker submission, but validation passes
    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Sell,
            OrderType::Limit,
            Decimal::from(100),
            Some(Decimal::from(50000)),
            None,
        )
        .await;

    // Should fail at broker stage, not validation
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker"));
}

#[tokio::test]
async fn test_validation_allows_valid_small_order() {
    let engine = create_engine();

    // Small order within buying power
    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(1),
            Some(Decimal::from(50000)),
            None,
        )
        .await;

    // Should pass validation, fail at broker stage
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker"));
}

#[tokio::test]
async fn test_validation_allows_boundary_order() {
    let engine = create_engine();

    // Order exactly at buying power limit (100k)
    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(2),
            Some(Decimal::from(50000)), // 2 * 50000 = 100000
            None,
        )
        .await;

    // Should pass validation
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker")); // Fails at broker, not validation
}

// ============================================================================
// Account Information Tests
// ============================================================================

#[tokio::test]
async fn test_get_demo_account_info() {
    let engine = create_engine();

    let account = engine
        .get_account_info("DEMO_ACCOUNT".to_string())
        .await
        .unwrap();

    assert_eq!(account.account_id, "DEMO_ACCOUNT");
    assert_eq!(account.total_value, Decimal::from(100000));
    assert_eq!(account.cash_balance, Decimal::from(50000));
    assert_eq!(account.buying_power, Decimal::from(100000));
    assert_eq!(account.maintenance_margin, Decimal::ZERO);
    assert_eq!(account.day_trading_buying_power, Decimal::from(200000));
}

#[tokio::test]
async fn test_get_nonexistent_account() {
    let engine = create_engine();

    let result = engine.get_account_info("NONEXISTENT".to_string()).await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("not found"));
}

#[tokio::test]
async fn test_get_account_info_case_sensitive() {
    let engine = create_engine();

    let result = engine.get_account_info("demo_account".to_string()).await;

    assert!(result.is_err());
    assert!(result.unwrap_err().contains("not found"));
}

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

#[tokio::test]
async fn test_get_positions_initially_empty() {
    let engine = create_engine();

    let positions = engine.get_positions(None).await.unwrap();

    assert!(positions.is_empty());
}

#[tokio::test]
async fn test_get_positions_with_symbol_filter_empty() {
    let engine = create_engine();

    let positions = engine.get_positions(Some("BTCUSD".to_string())).await.unwrap();

    assert!(positions.is_empty());
}

#[tokio::test]
async fn test_get_positions_multiple_filters() {
    let engine = create_engine();

    // Test various symbol filters on empty positions
    let btc = engine.get_positions(Some("BTCUSD".to_string())).await.unwrap();
    let eth = engine.get_positions(Some("ETHUSD".to_string())).await.unwrap();
    let sol = engine.get_positions(Some("SOLUSD".to_string())).await.unwrap();

    assert!(btc.is_empty());
    assert!(eth.is_empty());
    assert!(sol.is_empty());
}

// ============================================================================
// Market Data Subscription Tests
// ============================================================================

#[tokio::test]
async fn test_subscribe_single_symbol_market_data() {
    let engine = create_engine();

    let result = engine
        .subscribe_market_data(vec!["BTCUSD".to_string()])
        .await;

    assert!(result.is_ok());
    let _receiver = result.unwrap();
}

#[tokio::test]
async fn test_subscribe_multiple_symbols_market_data() {
    let engine = create_engine();

    let result = engine
        .subscribe_market_data(vec![
            "BTCUSD".to_string(),
            "ETHUSD".to_string(),
            "SOLUSD".to_string(),
        ])
        .await;

    assert!(result.is_ok());
}

#[tokio::test]
async fn test_subscribe_empty_symbols_list() {
    let engine = create_engine();

    let result = engine.subscribe_market_data(vec![]).await;

    assert!(result.is_ok());
}

#[tokio::test]
async fn test_subscribe_order_updates_without_account() {
    let engine = create_engine();

    let result = engine.subscribe_order_updates(None).await;

    assert!(result.is_ok());
}

#[tokio::test]
async fn test_subscribe_order_updates_with_account() {
    let engine = create_engine();

    let result = engine
        .subscribe_order_updates(Some("DEMO_ACCOUNT".to_string()))
        .await;

    assert!(result.is_ok());
}

// ============================================================================
// Trading Statistics Tests
// ============================================================================

#[tokio::test]
async fn test_trading_stats_initial_state() {
    let engine = create_engine();

    let stats = engine.get_trading_stats().await;

    assert_eq!(stats.total_orders, 0);
    assert_eq!(stats.filled_orders, 0);
}

// ============================================================================
// Market Making Tests
// ============================================================================

#[tokio::test]
async fn test_update_market_making_quotes() {
    let engine = create_engine();

    let result = engine
        .update_market_making_quotes(
            "BTCUSD".to_string(),
            Decimal::from(49900), // bid
            Decimal::from(50100), // ask
            Decimal::from(10),    // bid qty
            Decimal::from(10),    // ask qty
        )
        .await;

    assert!(result.is_ok());
}

#[tokio::test]
async fn test_detect_arbitrage_opportunity() {
    let engine = create_engine();

    let opportunity = engine
        .detect_arbitrage_opportunity(
            "BTCUSD".to_string(),
            Decimal::from(50000), // exchange 1
            Decimal::from(50500), // exchange 2
            10.0,                 // min 10 bps profit
        )
        .await;

    // Should detect arbitrage (1% spread)
    assert!(opportunity.is_some());

    let arb = opportunity.unwrap();
    assert_eq!(arb.symbol, "BTCUSD");
    assert_eq!(arb.buy_price, Decimal::from(50000));
    assert_eq!(arb.sell_price, Decimal::from(50500));
}

#[tokio::test]
async fn test_no_arbitrage_when_spread_too_small() {
    let engine = create_engine();

    let opportunity = engine
        .detect_arbitrage_opportunity(
            "BTCUSD".to_string(),
            Decimal::from(50000),
            Decimal::from(50010), // Only 0.02% spread
            10.0,                 // Need 10 bps
        )
        .await;

    // Should NOT detect arbitrage (spread too small)
    assert!(opportunity.is_none());
}

// ============================================================================
// Edge Cases & Error Handling
// ============================================================================

#[tokio::test]
async fn test_fractional_quantity_validation() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Buy,
            OrderType::Market,
            Decimal::new(15, 1), // 1.5
            None,
            None,
        )
        .await;

    // Fractional quantities should be allowed
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker")); // Passes validation
}

#[tokio::test]
async fn test_very_large_quantity() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Sell,
            OrderType::Limit,
            Decimal::from(1_000_000_000),
            Some(Decimal::from(50000)),
            None,
        )
        .await;

    // Large quantities should be allowed (sell doesn't check buying power)
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker"));
}

#[tokio::test]
async fn test_very_small_price() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "SHITCOIN".to_string(),
            OrderSide::Buy,
            OrderType::Limit,
            Decimal::from(1_000_000),
            Some(Decimal::new(1, 6)), // $0.000001
            None,
        )
        .await;

    // Very small prices should be allowed
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker"));
}

#[tokio::test]
async fn test_very_large_price() {
    let engine = create_engine();

    let result = engine
        .submit_order(
            "BTCUSD".to_string(),
            OrderSide::Sell,
            OrderType::Limit,
            Decimal::from(1),
            Some(Decimal::from(10_000_000)), // $10M per BTC
            None,
        )
        .await;

    // Large prices should be allowed
    assert!(result.is_err());
    assert!(result.unwrap_err().contains("broker"));
}

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

#[tokio::test]
async fn test_concurrent_account_queries() {
    let engine = Arc::new(create_engine());

    let mut handles = vec![];

    for _ in 0..10 {
        let engine_clone = Arc::clone(&engine);
        let handle = tokio::spawn(async move {
            engine_clone
                .get_account_info("DEMO_ACCOUNT".to_string())
                .await
        });
        handles.push(handle);
    }

    let results: Vec<_> = futures::future::join_all(handles).await;

    // All should succeed
    for result in results {
        assert!(result.unwrap().is_ok());
    }
}

#[tokio::test]
async fn test_concurrent_position_queries() {
    let engine = Arc::new(create_engine());

    let mut handles = vec![];

    for _ in 0..10 {
        let engine_clone = Arc::clone(&engine);
        let handle = tokio::spawn(async move { engine_clone.get_positions(None).await });
        handles.push(handle);
    }

    let results: Vec<_> = futures::future::join_all(handles).await;

    // All should succeed
    for result in results {
        assert!(result.unwrap().is_ok());
    }
}

#[tokio::test]
async fn test_concurrent_validation_attempts() {
    let engine = Arc::new(create_engine());

    let mut handles = vec![];

    for i in 0..10 {
        let engine_clone = Arc::clone(&engine);
        let handle = tokio::spawn(async move {
            engine_clone
                .submit_order(
                    format!("SYM{}", i),
                    OrderSide::Buy,
                    OrderType::Market,
                    Decimal::from(1),
                    None,
                    None,
                )
                .await
        });
        handles.push(handle);
    }

    let results: Vec<_> = futures::future::join_all(handles).await;

    // All should complete (fail at broker stage)
    for result in results {
        assert!(result.is_ok()); // Task completed
        assert!(result.unwrap().is_err()); // But order submission failed
    }
}
