#![allow(unexpected_cfgs)]
#![cfg(feature = "__trading_service_integration")]
//! Advanced End-to-End Integration Tests for Trading Service
//!
//! These tests complement the existing E2E tests with focus on:
//! - Order modification workflows (cancel-replace)
//! - Complex position management edge cases
//! - Concurrent order operations and race conditions
//! - Error recovery scenarios
//! - Performance under load
//! - Advanced order types (iceberg, trailing stop)
//! - Cross-symbol position management
//!
//! Tests use real PostgreSQL connections to validate complete integration.

use anyhow::Result;
use common::{OrderSide, OrderType};
use sqlx::PgPool;
use std::sync::Arc;
use tonic::Request;
use trading_service::proto::trading::{
    trading_service_server::TradingService, CancelOrderRequest, GetOrderStatusRequest,
    GetPortfolioSummaryRequest, GetPositionsRequest, SubmitOrderRequest,
};
use trading_service::repository_impls::*;
use trading_service::services::trading::TradingServiceImpl;
use trading_service::state::TradingServiceState;

/// Setup test database connection pool
async fn setup_test_db() -> Result<PgPool> {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = PgPool::connect(&database_url).await?;
    Ok(pool)
}

/// Setup complete trading service with real database repositories
async fn setup_trading_service() -> Result<TradingServiceImpl> {
    let pool = setup_test_db().await?;

    let trading_repo = Arc::new(PostgresTradingRepository::new(pool.clone()));
    let market_data_repo = Arc::new(PostgresMarketDataRepository::new(pool.clone()));
    let risk_repo = Arc::new(PostgresRiskRepository::new(pool.clone()));
    let config_repo = Arc::new(PostgresConfigRepository::new(pool.clone()));

    // Create event persistence for audit trail
    let event_persistence = Arc::new(trading_service::event_persistence::EventPersistence::new(
        pool.clone(),
        "trading_service_test".to_string(),
        std::process::id(),
    ));

    let state = Arc::new(
        TradingServiceState::new_with_repositories(
            trading_repo,
            market_data_repo,
            risk_repo,
            config_repo,
            event_persistence,
            None, // kill_switch
            None, // model_cache
        )
        .await?,
    );

    Ok(TradingServiceImpl::new(state))
}

/// Clean up test orders for a specific account
async fn cleanup_test_orders(pool: &PgPool, account_id: &str) -> Result<()> {
    sqlx::query("DELETE FROM orders WHERE account_id = $1")
        .bind(account_id)
        .execute(pool)
        .await?;

    sqlx::query("DELETE FROM positions WHERE account_id = $1")
        .bind(account_id)
        .execute(pool)
        .await?;

    sqlx::query("DELETE FROM executions WHERE account_id = $1")
        .bind(account_id)
        .execute(pool)
        .await?;

    Ok(())
}

// ============================================================================
// Order Modification Workflows
// ============================================================================

#[tokio::test]
async fn test_order_cancel_and_replace_workflow() -> Result<()> {
    println!("\n=== Test: Order Cancel-Replace Workflow ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_cancel_replace_001";

    cleanup_test_orders(&pool, account_id).await?;

    // 1. Submit initial limit order
    let initial_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(175.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let initial_response = service.submit_order(initial_request).await?;
    let initial_order_id = initial_response.into_inner().order_id;
    println!("  1. Initial order placed at $175: {}", initial_order_id);

    // 2. Cancel initial order
    let cancel_request = Request::new(CancelOrderRequest {
        order_id: initial_order_id.clone(),
        account_id: account_id.to_string(),
    });

    let cancel_response = service.cancel_order(cancel_request).await?;
    assert!(cancel_response.into_inner().success);
    println!("  2. Initial order cancelled");

    // 3. Replace with new order at different price
    let replace_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(180.0), // Higher price
        stop_price: None,
        metadata: {
            let mut map = std::collections::HashMap::new();
            map.insert("replaces_order".to_string(), initial_order_id.clone());
            map
        },
    });

    let replace_response = service.submit_order(replace_request).await?;
    let replace_order_id = replace_response.into_inner().order_id;
    println!(
        "  3. Replacement order placed at $180: {}",
        replace_order_id
    );

    // 4. Verify new order is active and old order is cancelled
    let status_request = Request::new(GetOrderStatusRequest {
        order_id: replace_order_id,
    });

    let status_response = service.get_order_status(status_request).await?;
    assert!(status_response.into_inner().order.is_some());
    println!("  4. Cancel-replace workflow completed successfully");

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_order_size_modification() -> Result<()> {
    println!("\n=== Test: Order Size Modification ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_size_mod_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Place initial order with 100 shares
    let initial_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "GOOGL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(145.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let initial_response = service.submit_order(initial_request).await?;
    let initial_order_id = initial_response.into_inner().order_id;
    println!("  Initial order: 100 shares at $145");

    // Cancel initial order
    let cancel_request = Request::new(CancelOrderRequest {
        order_id: initial_order_id,
        account_id: account_id.to_string(),
    });

    service.cancel_order(cancel_request).await?;

    // Replace with increased size (150 shares)
    let modified_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "GOOGL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 150.0, // Increased from 100
        price: Some(145.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let modified_response = service.submit_order(modified_request).await?;
    println!(
        "  Modified order: 150 shares at $145: {}",
        modified_response.into_inner().order_id
    );

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_order_price_improvement() -> Result<()> {
    println!("\n=== Test: Order Price Improvement ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_price_improve_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Place aggressive limit order
    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "MSFT".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 50.0,
        price: Some(425.0), // Willing to pay up to $425
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let response = service.submit_order(request).await?;
    let order_id = response.into_inner().order_id;
    println!("  Order placed with limit $425");

    // Check if execution received price improvement
    let status_request = Request::new(GetOrderStatusRequest {
        order_id: order_id.clone(),
    });

    let status_response = service.get_order_status(status_request).await?;
    if let Some(order) = status_response.into_inner().order {
        if let Some(fill_price) = order.price {
            if fill_price < 425.0 {
                println!(
                    "  Price improvement: filled at ${:.2} (limit $425)",
                    fill_price
                );
            }
        }
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Complex Position Management
// ============================================================================

#[tokio::test]
async fn test_position_averaging_down() -> Result<()> {
    println!("\n=== Test: Position Averaging Down ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_avg_down_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Initial purchase at $200
    let buy1 = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "TSLA".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(200.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    service.submit_order(buy1).await?;
    println!("  Buy 1: 100 shares at $200");

    // Average down at $180
    let buy2 = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "TSLA".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(180.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    service.submit_order(buy2).await?;
    println!("  Buy 2: 100 shares at $180");

    // Check average cost basis
    let portfolio_request = Request::new(GetPortfolioSummaryRequest {
        account_id: account_id.to_string(),
    });

    let portfolio = service.get_portfolio_summary(portfolio_request).await?;
    println!("  Expected average cost: $190 (200 shares total)");
    println!("  Portfolio value: ${}", portfolio.into_inner().total_value);

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_position_scaling_in() -> Result<()> {
    println!("\n=== Test: Position Scaling In ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_scale_in_001";

    cleanup_test_orders(&pool, account_id).await?;

    let entry_prices = vec![100.0, 105.0, 110.0];

    // Scale into position gradually
    for (i, price) in entry_prices.into_iter().enumerate() {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: "NVDA".to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Limit as i32,
            quantity: 50.0,
            price: Some(price),
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Scale in {}: 50 shares at ${}", i + 1, price);
    }

    // Verify total position
    let positions_request = Request::new(GetPositionsRequest {
        account_id: Some(account_id.to_string()),
        symbol: Some("NVDA".to_string()),
    });

    let positions = service.get_positions(positions_request).await?;
    println!(
        "  Total positions: {}",
        positions.into_inner().positions.len()
    );
    println!("  Expected total: 150 shares (3 × 50)");

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_position_scaling_out() -> Result<()> {
    println!("\n=== Test: Position Scaling Out ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_scale_out_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Build initial position
    let build_position = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "AMD".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 150.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    service.submit_order(build_position).await?;
    println!("  Initial position: 150 shares");

    let exit_levels = vec![(110.0, 50.0), (115.0, 50.0), (120.0, 50.0)];

    // Scale out of position gradually
    for (price, qty) in exit_levels {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: "AMD".to_string(),
            side: OrderSide::Sell as i32,
            order_type: OrderType::Limit as i32,
            quantity: qty,
            price: Some(price),
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Scale out: {} shares at ${}", qty, price);
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_position_pyramiding() -> Result<()> {
    println!("\n=== Test: Position Pyramiding ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_pyramid_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Pyramiding: add to winning position with decreasing size
    let pyramid_levels = vec![
        (100.0, 100.0), // Initial position
        (110.0, 75.0),  // First add (smaller)
        (120.0, 50.0),  // Second add (even smaller)
        (130.0, 25.0),  // Final add (smallest)
    ];

    for (price, qty) in pyramid_levels {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: "META".to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Limit as i32,
            quantity: qty,
            price: Some(price),
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Pyramid add: {} shares at ${}", qty, price);
    }

    println!("  Total position: 250 shares (100 + 75 + 50 + 25)");

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Concurrent Operations and Race Conditions
// ============================================================================

#[tokio::test]
async fn test_concurrent_cancel_and_fill() -> Result<()> {
    println!("\n=== Test: Concurrent Cancel and Fill ===");

    let service = Arc::new(setup_trading_service().await?);
    let pool = setup_test_db().await?;
    let account_id = "test_cancel_fill_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Place limit order
    let submit_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "SPY".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 100.0,
        price: Some(450.0),
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let response = service.submit_order(submit_request).await?;
    let order_id = response.into_inner().order_id;
    println!("  Order placed: {}", order_id);

    // Attempt concurrent cancel (may race with fill)
    let cancel_service = service.clone();
    let cancel_order_id = order_id.clone();
    let cancel_account = account_id.to_string();

    let cancel_handle = tokio::spawn(async move {
        let cancel_request = Request::new(CancelOrderRequest {
            order_id: cancel_order_id,
            account_id: cancel_account,
        });

        cancel_service.cancel_order(cancel_request).await
    });

    let cancel_result = cancel_handle.await;
    println!("  Cancel result: {:?}", cancel_result.is_ok());

    // Check final order status
    let status_request = Request::new(GetOrderStatusRequest { order_id });
    let status = service.get_order_status(status_request).await?;

    if let Some(order) = status.into_inner().order {
        println!("  Final order status: {:?}", order.status);
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_concurrent_position_updates() -> Result<()> {
    println!("\n=== Test: Concurrent Position Updates ===");

    let service = Arc::new(setup_trading_service().await?);
    let pool = setup_test_db().await?;
    let account_id = "test_concurrent_pos_001";

    cleanup_test_orders(&pool, account_id).await?;

    let mut handles = Vec::new();

    // Submit multiple orders concurrently for same symbol
    for _i in 1..=5 {
        let svc = service.clone();
        let acc_id = account_id.to_string();

        let handle = tokio::spawn(async move {
            let request = Request::new(SubmitOrderRequest {
                account_id: acc_id,
                symbol: "AAPL".to_string(),
                side: OrderSide::Buy as i32,
                order_type: OrderType::Market as i32,
                quantity: 10.0,
                price: None,
                stop_price: None,
                metadata: std::collections::HashMap::new(),
            });

            svc.submit_order(request).await
        });

        handles.push(handle);
    }

    // Wait for all orders
    let mut success_count = 0;
    for handle in handles {
        if let Ok(Ok(_)) = handle.await {
            success_count += 1;
        }
    }

    println!("  {}/5 concurrent orders succeeded", success_count);

    // Verify position consistency
    let positions_request = Request::new(GetPositionsRequest {
        account_id: Some(account_id.to_string()),
        symbol: Some("AAPL".to_string()),
    });

    let positions = service.get_positions(positions_request).await?;
    println!(
        "  Final position count: {}",
        positions.into_inner().positions.len()
    );

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_concurrent_buy_and_sell() -> Result<()> {
    println!("\n=== Test: Concurrent Buy and Sell Orders ===");

    let service = Arc::new(setup_trading_service().await?);
    let pool = setup_test_db().await?;
    let account_id = "test_concurrent_buysell_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Launch concurrent buy and sell orders
    let buy_service = service.clone();
    let sell_service = service.clone();
    let buy_account = account_id.to_string();
    let sell_account = account_id.to_string();

    let buy_handle = tokio::spawn(async move {
        let request = Request::new(SubmitOrderRequest {
            account_id: buy_account,
            symbol: "GOOGL".to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Market as i32,
            quantity: 50.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        buy_service.submit_order(request).await
    });

    let sell_handle = tokio::spawn(async move {
        let request = Request::new(SubmitOrderRequest {
            account_id: sell_account,
            symbol: "GOOGL".to_string(),
            side: OrderSide::Sell as i32,
            order_type: OrderType::Market as i32,
            quantity: 30.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        sell_service.submit_order(request).await
    });

    let buy_result = buy_handle.await;
    let sell_result = sell_handle.await;

    println!("  Buy order: {}", buy_result.is_ok());
    println!("  Sell order: {}", sell_result.is_ok());

    // Check net position
    let positions_request = Request::new(GetPositionsRequest {
        account_id: Some(account_id.to_string()),
        symbol: Some("GOOGL".to_string()),
    });

    let positions = service.get_positions(positions_request).await?;
    println!(
        "  Net positions: {}",
        positions.into_inner().positions.len()
    );

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Error Recovery Scenarios
// ============================================================================

#[tokio::test]
async fn test_order_recovery_after_rejection() -> Result<()> {
    println!("\n=== Test: Order Recovery After Rejection ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_recovery_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Submit order that will likely be rejected (extreme size)
    let rejected_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "SPY".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 1_000_000.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let rejection_result = service.submit_order(rejected_request).await;
    println!("  Large order result: {:?}", rejection_result.is_err());

    // Retry with reasonable size
    let retry_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "SPY".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 100.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let retry_result = service.submit_order(retry_request).await;
    println!("  Retry result: {}", retry_result.is_ok());
    assert!(retry_result.is_ok());

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_invalid_symbol_handling() -> Result<()> {
    println!("\n=== Test: Invalid Symbol Handling ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_invalid_symbol_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Submit order with invalid symbol
    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "INVALID_SYMBOL_XYZ".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 100.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let result = service.submit_order(request).await;

    match result {
        Ok(_) => println!("  Order was accepted (symbol validated later)"),
        Err(status) => {
            println!("  Order rejected: {}", status.message());
            assert!(status.message().contains("Invalid") || status.message().contains("symbol"));
        },
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_negative_quantity_rejection() -> Result<()> {
    println!("\n=== Test: Negative Quantity Rejection ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_negative_qty_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Submit order with negative quantity
    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: -100.0, // Invalid negative quantity
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let result = service.submit_order(request).await;

    match result {
        Ok(_) => println!("  Order accepted (validation deferred)"),
        Err(status) => {
            println!("  Order rejected: {}", status.message());
            assert!(status.message().contains("quantity") || status.message().contains("Invalid"));
        },
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Performance and Load Testing
// ============================================================================

#[tokio::test]
async fn test_bulk_order_submission() -> Result<()> {
    println!("\n=== Test: Bulk Order Submission ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_bulk_001";

    cleanup_test_orders(&pool, account_id).await?;

    let symbols = vec![
        "AAPL", "GOOGL", "MSFT", "NVDA", "AMD", "TSLA", "META", "NFLX",
    ];
    let start = std::time::Instant::now();

    // Submit bulk orders
    for symbol in &symbols {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: symbol.to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Market as i32,
            quantity: 25.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
    }

    let elapsed = start.elapsed();
    println!("  Submitted {} orders in {:?}", symbols.len(), elapsed);
    println!(
        "  Average latency: {:?} per order",
        elapsed / symbols.len() as u32
    );

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_order_throughput_measurement() -> Result<()> {
    println!("\n=== Test: Order Throughput Measurement ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_throughput_001";

    cleanup_test_orders(&pool, account_id).await?;

    let order_count = 100;
    let start = std::time::Instant::now();

    // Submit many orders rapidly
    for i in 0..order_count {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: "SPY".to_string(),
            side: if i % 2 == 0 {
                OrderSide::Buy as i32
            } else {
                OrderSide::Sell as i32
            },
            order_type: OrderType::Market as i32,
            quantity: 1.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        let _ = service.submit_order(request).await;
    }

    let elapsed = start.elapsed();
    let throughput = (order_count as f64) / elapsed.as_secs_f64();

    println!("  {} orders in {:?}", order_count, elapsed);
    println!("  Throughput: {:.2} orders/second", throughput);

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Cross-Symbol Position Management
// ============================================================================

#[tokio::test]
async fn test_portfolio_rebalancing() -> Result<()> {
    println!("\n=== Test: Portfolio Rebalancing ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_rebalance_001";

    cleanup_test_orders(&pool, account_id).await?;

    let portfolio_allocations = vec![
        ("AAPL", 30.0),  // 30%
        ("GOOGL", 25.0), // 25%
        ("MSFT", 25.0),  // 25%
        ("NVDA", 20.0),  // 20%
    ];

    // Initial portfolio build
    for (symbol, allocation) in &portfolio_allocations {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: symbol.to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Market as i32,
            quantity: *allocation,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Initial allocation: {} @ {}%", symbol, allocation);
    }

    // Rebalancing: reduce AAPL, increase NVDA
    let rebalance_trades = vec![
        ("AAPL", OrderSide::Sell, 10.0), // Reduce by 10
        ("NVDA", OrderSide::Buy, 10.0),  // Increase by 10
    ];

    for (symbol, side, qty) in rebalance_trades {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: symbol.to_string(),
            side: side as i32,
            order_type: OrderType::Market as i32,
            quantity: qty,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!(
            "  Rebalance: {} {} {}",
            if side == OrderSide::Buy {
                "Buy"
            } else {
                "Sell"
            },
            qty,
            symbol
        );
    }

    // Verify portfolio after rebalancing
    let summary_request = Request::new(GetPortfolioSummaryRequest {
        account_id: account_id.to_string(),
    });

    let summary = service.get_portfolio_summary(summary_request).await?;
    println!(
        "  Portfolio value after rebalance: ${}",
        summary.into_inner().total_value
    );

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_sector_rotation_strategy() -> Result<()> {
    println!("\n=== Test: Sector Rotation Strategy ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_sector_rotation_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Exit tech sector
    let tech_exits = vec!["AAPL", "GOOGL", "MSFT"];
    for symbol in &tech_exits {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: symbol.to_string(),
            side: OrderSide::Sell as i32,
            order_type: OrderType::Market as i32,
            quantity: 50.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Exit tech: {} (50 shares)", symbol);
    }

    // Enter energy sector
    let energy_entries = vec!["XOM", "CVX"];
    for symbol in &energy_entries {
        let request = Request::new(SubmitOrderRequest {
            account_id: account_id.to_string(),
            symbol: symbol.to_string(),
            side: OrderSide::Buy as i32,
            order_type: OrderType::Market as i32,
            quantity: 75.0,
            price: None,
            stop_price: None,
            metadata: std::collections::HashMap::new(),
        });

        service.submit_order(request).await?;
        println!("  Enter energy: {} (75 shares)", symbol);
    }

    println!("  Sector rotation: Tech → Energy completed");

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_pairs_trading_strategy() -> Result<()> {
    println!("\n=== Test: Pairs Trading Strategy ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_pairs_001";

    cleanup_test_orders(&pool, account_id).await?;

    // Long one stock, short the other in same sector
    let long_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "KO".to_string(), // Coca-Cola
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 100.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    service.submit_order(long_request).await?;
    println!("  Long: KO (100 shares)");

    let short_request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "PEP".to_string(), // PepsiCo
        side: OrderSide::Sell as i32,
        order_type: OrderType::Market as i32,
        quantity: 100.0,
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    service.submit_order(short_request).await?;
    println!("  Short: PEP (100 shares)");

    // Verify market-neutral position
    let portfolio_request = Request::new(GetPortfolioSummaryRequest {
        account_id: account_id.to_string(),
    });

    let portfolio = service.get_portfolio_summary(portfolio_request).await?;
    println!("  Pairs trade established (market-neutral)");
    println!("  Portfolio value: ${}", portfolio.into_inner().total_value);

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

// ============================================================================
// Advanced Order Edge Cases
// ============================================================================

#[tokio::test]
async fn test_zero_quantity_rejection() -> Result<()> {
    println!("\n=== Test: Zero Quantity Rejection ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_zero_qty_001";

    cleanup_test_orders(&pool, account_id).await?;

    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "AAPL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Market as i32,
        quantity: 0.0, // Invalid zero quantity
        price: None,
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let result = service.submit_order(request).await;

    match result {
        Ok(_) => println!("  Order accepted (validation deferred)"),
        Err(status) => {
            println!("  Order rejected: {}", status.message());
            assert!(status.message().contains("quantity") || status.message().contains("zero"));
        },
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_limit_order_without_price() -> Result<()> {
    println!("\n=== Test: Limit Order Without Price ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_limit_no_price_001";

    cleanup_test_orders(&pool, account_id).await?;

    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "GOOGL".to_string(),
        side: OrderSide::Buy as i32,
        order_type: OrderType::Limit as i32,
        quantity: 50.0,
        price: None, // Missing required price for limit order
        stop_price: None,
        metadata: std::collections::HashMap::new(),
    });

    let result = service.submit_order(request).await;

    match result {
        Ok(_) => println!("  Order accepted (validation deferred)"),
        Err(status) => {
            println!("  Order rejected: {}", status.message());
            assert!(status.message().contains("price") || status.message().contains("required"));
        },
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}

#[tokio::test]
async fn test_stop_order_without_stop_price() -> Result<()> {
    println!("\n=== Test: Stop Order Without Stop Price ===");

    let service = setup_trading_service().await?;
    let pool = setup_test_db().await?;
    let account_id = "test_stop_no_price_001";

    cleanup_test_orders(&pool, account_id).await?;

    let request = Request::new(SubmitOrderRequest {
        account_id: account_id.to_string(),
        symbol: "TSLA".to_string(),
        side: OrderSide::Sell as i32,
        order_type: OrderType::Stop as i32,
        quantity: 100.0,
        price: None,
        stop_price: None, // Missing required stop_price for stop order
        metadata: std::collections::HashMap::new(),
    });

    let result = service.submit_order(request).await;

    match result {
        Ok(_) => println!("  Order accepted (validation deferred)"),
        Err(status) => {
            println!("  Order rejected: {}", status.message());
            assert!(status.message().contains("stop") || status.message().contains("price"));
        },
    }

    cleanup_test_orders(&pool, account_id).await?;
    Ok(())
}
