//! Integration tests for universe selection module

use trading_agent_service::universe::{AssetClass, Region, UniverseCriteria, UniverseSelector};

#[tokio::test]
async fn test_select_universe_with_default_criteria() {
    // Setup database connection
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    // Run migrations
    sqlx::migrate!("../../migrations")
        .run(&pool)
        .await
        .expect("Failed to run migrations");

    let selector = UniverseSelector::new(pool);

    // Test with default criteria
    let criteria = UniverseCriteria::default();
    let result = selector.select_universe(criteria).await;

    assert!(
        result.is_ok(),
        "Universe selection should succeed with default criteria"
    );

    let universe = result.expect("Universe should be present");

    // Verify universe properties
    assert!(!universe.universe_id.is_empty());
    assert!(!universe.instruments.is_empty(), "Should have instruments");
    assert_eq!(
        universe.metrics.total_instruments,
        universe.instruments.len()
    );
    assert!(universe.metrics.avg_liquidity_score > 0.0);
    assert!(universe.metrics.avg_volatility > 0.0);
}

#[tokio::test]
async fn test_select_universe_with_high_liquidity() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with high liquidity requirement
    let criteria = UniverseCriteria {
        min_liquidity: 0.90, // Only ES.FUT, NQ.FUT, CL.FUT qualify
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // All instruments should have liquidity >= 0.90
    for instrument in &universe.instruments {
        assert!(
            instrument.liquidity_score >= 0.90,
            "Instrument {} has liquidity {} which is below threshold",
            instrument.symbol,
            instrument.liquidity_score
        );
    }
}

#[tokio::test]
async fn test_select_universe_with_low_volatility() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with low volatility requirement
    let criteria = UniverseCriteria {
        max_volatility: 0.20, // Only ES.FUT, ZN.FUT, 6E.FUT qualify
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // All instruments should have volatility <= 0.20
    for instrument in &universe.instruments {
        assert!(
            instrument.volatility <= 0.20,
            "Instrument {} has volatility {} which exceeds threshold",
            instrument.symbol,
            instrument.volatility
        );
    }
}

#[tokio::test]
async fn test_select_universe_by_asset_class() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with currencies only
    let criteria = UniverseCriteria {
        asset_classes: vec![AssetClass::Currencies],
        regions: vec![Region::Global], // 6E.FUT is in Global region
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // Should only include 6E.FUT
    assert_eq!(universe.instruments.len(), 1);
    assert_eq!(universe.instruments[0].symbol.as_str(), "6E.FUT");
}

#[tokio::test]
async fn test_select_universe_by_region() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with Global region only
    let criteria = UniverseCriteria {
        regions: vec![Region::Global],
        asset_classes: vec![
            AssetClass::Futures,
            AssetClass::Currencies,
            AssetClass::Commodities,
        ],
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // Should only include instruments from Global region
    for instrument in &universe.instruments {
        assert_eq!(instrument.region, Region::Global);
    }
}

#[tokio::test]
async fn test_get_universe_by_id() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Create universe
    let criteria = UniverseCriteria::default();
    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to create universe");

    // Retrieve universe by ID
    let retrieved = selector.get_universe(&universe.universe_id).await;

    assert!(retrieved.is_ok());
    let retrieved_universe = retrieved.expect("Universe should be retrieved");

    assert_eq!(retrieved_universe.universe_id, universe.universe_id);
    assert_eq!(
        retrieved_universe.instruments.len(),
        universe.instruments.len()
    );
}

#[tokio::test]
async fn test_get_nonexistent_universe() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Try to get non-existent universe
    let result = selector.get_universe("nonexistent_id").await;

    assert!(result.is_err());
}

#[tokio::test]
async fn test_update_criteria() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Create universe
    let criteria = UniverseCriteria::default();
    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to create universe");

    // Update criteria
    let new_criteria = UniverseCriteria {
        min_liquidity: 0.95, // Very high threshold
        ..UniverseCriteria::default()
    };

    let result = selector
        .update_criteria(&universe.universe_id, new_criteria)
        .await;

    assert!(result.is_ok());
    let updated_universe = result.expect("Update should succeed");

    // New universe should have different ID (new universe created)
    assert_ne!(updated_universe.universe_id, universe.universe_id);

    // New universe should have fewer instruments (higher threshold)
    assert!(updated_universe.instruments.len() <= universe.instruments.len());
}

#[tokio::test]
async fn test_universe_performance() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

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

    let criteria = UniverseCriteria::default();
    let _universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    let duration = start.elapsed();

    // Performance target: < 1 second
    assert!(
        duration.as_millis() < 1000,
        "Universe selection took {}ms (target: <1000ms)",
        duration.as_millis()
    );

    println!("Universe selection completed in {}ms", duration.as_millis());
}

#[tokio::test]
async fn test_invalid_criteria_min_liquidity() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria {
        min_liquidity: 1.5, // Invalid (> 1.0)
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_err());
}

#[tokio::test]
async fn test_invalid_criteria_max_volatility() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria {
        max_volatility: -0.1, // Invalid (< 0.0)
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_err());
}

#[tokio::test]
async fn test_no_instruments_match() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Set impossible criteria
    let criteria = UniverseCriteria {
        min_liquidity: 0.99, // Very high
        max_volatility: 0.01, // Very low — no instrument can satisfy both
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_err());
}

// ============================================================================
// EDGE CASE TESTS
// ============================================================================

#[tokio::test]
async fn test_extreme_liquidity_threshold() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with extremely high liquidity threshold
    let criteria = UniverseCriteria {
        min_liquidity: 0.99, // Only instruments with 99%+ liquidity
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    // Should fail because no instruments meet this threshold
    assert!(
        result.is_err(),
        "Should fail with extreme liquidity threshold"
    );
}

#[tokio::test]
async fn test_minimal_liquidity_threshold() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with minimal liquidity threshold
    let criteria = UniverseCriteria {
        min_liquidity: 0.0, // Accept all instruments
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // Should include all instruments that pass other filters
    assert!(
        !universe.instruments.is_empty(),
        "Should have at least one instrument"
    );
}

#[tokio::test]
async fn test_single_symbol_universe() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Create criteria that only matches ES.FUT
    let criteria = UniverseCriteria {
        min_liquidity: 0.95, // Only ES.FUT has 0.95
        max_volatility: 0.20, // ES.FUT has 0.20
        asset_classes: vec![AssetClass::Futures],
        regions: vec![Region::NorthAmerica],
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // Should only have ES.FUT
    assert_eq!(universe.instruments.len(), 1);
    assert_eq!(universe.instruments[0].symbol.as_str(), "ES.FUT");
}

#[tokio::test]
async fn test_multiple_asset_classes() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with multiple asset classes
    let criteria = UniverseCriteria {
        asset_classes: vec![
            AssetClass::Futures,
            AssetClass::Currencies,
            AssetClass::Commodities,
        ],
        regions: vec![Region::NorthAmerica, Region::Global],
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // Should have instruments from multiple asset classes
    let mut asset_class_names = std::collections::HashSet::new();
    for instrument in &universe.instruments {
        asset_class_names.insert(format!("{:?}", instrument.asset_class));
    }

    assert!(
        asset_class_names.len() >= 2,
        "Should have instruments from multiple asset classes"
    );
}

#[tokio::test]
async fn test_market_cap_filtering() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Test with high market cap threshold
    let criteria = UniverseCriteria {
        min_market_cap: Some(8_000_000_000.0), // $8B - only ES.FUT and NQ.FUT
        ..UniverseCriteria::default()
    };

    let result = selector.select_universe(criteria).await;

    assert!(result.is_ok());
    let universe = result.expect("Universe should be present");

    // All instruments should have market cap >= $8B
    for instrument in &universe.instruments {
        if let Some(cap) = instrument.market_cap {
            assert!(
                cap >= 8_000_000_000.0,
                "Instrument {} has market cap ${} which is below threshold",
                instrument.symbol,
                cap
            );
        }
    }

    // Should only have ES.FUT and NQ.FUT
    assert!(universe.instruments.len() <= 2);
}

// ============================================================================
// DETERMINISM AND REPRODUCIBILITY TESTS
// ============================================================================

#[tokio::test]
async fn test_deterministic_results() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria::default();

    // Run selection twice with same criteria
    let universe1 = selector
        .select_universe(criteria.clone())
        .await
        .expect("First selection failed");
    let universe2 = selector
        .select_universe(criteria.clone())
        .await
        .expect("Second selection failed");

    // Results should be deterministic (same number of instruments)
    assert_eq!(
        universe1.instruments.len(),
        universe2.instruments.len(),
        "Results should be deterministic"
    );

    // Same symbols should be selected (in any order)
    let symbols1: std::collections::HashSet<_> = universe1
        .instruments
        .iter()
        .map(|i| i.symbol.as_str())
        .collect();
    let symbols2: std::collections::HashSet<_> = universe2
        .instruments
        .iter()
        .map(|i| i.symbol.as_str())
        .collect();

    assert_eq!(symbols1, symbols2, "Same symbols should be selected");
}

#[tokio::test]
async fn test_reproducible_metrics() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria::default();

    // Run selection twice
    let universe1 = selector
        .select_universe(criteria.clone())
        .await
        .expect("First selection failed");
    let universe2 = selector
        .select_universe(criteria.clone())
        .await
        .expect("Second selection failed");

    // Metrics should be identical
    assert_eq!(
        universe1.metrics.total_instruments,
        universe2.metrics.total_instruments
    );
    assert!(
        (universe1.metrics.avg_liquidity_score - universe2.metrics.avg_liquidity_score).abs()
            < 1e-10
    );
    assert!((universe1.metrics.avg_volatility - universe2.metrics.avg_volatility).abs() < 1e-10);
    assert!((universe1.metrics.avg_spread_bps - universe2.metrics.avg_spread_bps).abs() < 1e-10);
}

// ============================================================================
// PERFORMANCE TESTS
// ============================================================================

#[tokio::test]
async fn test_performance_with_multiple_filters() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

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

    // Test with complex criteria
    let criteria = UniverseCriteria {
        min_liquidity: 0.85,
        max_volatility: 0.30,
        asset_classes: vec![
            AssetClass::Futures,
            AssetClass::Currencies,
            AssetClass::Commodities,
        ],
        regions: vec![Region::NorthAmerica, Region::Global],
        min_market_cap: Some(4_000_000_000.0),
        ..UniverseCriteria::default()
    };

    let _universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    let duration = start.elapsed();

    // Performance target: < 1 second
    assert!(
        duration.as_millis() < 1000,
        "Universe selection with multiple filters took {}ms (target: <1000ms)",
        duration.as_millis()
    );

    println!(
        "Complex universe selection completed in {}ms",
        duration.as_millis()
    );
}

#[tokio::test]
async fn test_performance_sequential_selections() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

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

    // Run 10 sequential selections
    for _ in 0..10 {
        let criteria = UniverseCriteria::default();
        let _universe = selector
            .select_universe(criteria)
            .await
            .expect("Selection failed");
    }

    let duration = start.elapsed();
    let avg_duration = duration.as_millis() / 10;

    // Average should be well under 1 second
    assert!(
        avg_duration < 1000,
        "Average universe selection took {}ms (target: <1000ms)",
        avg_duration
    );

    println!(
        "10 sequential selections completed in {}ms (avg: {}ms)",
        duration.as_millis(),
        avg_duration
    );
}

// ============================================================================
// METRICS VALIDATION TESTS
// ============================================================================

#[tokio::test]
async fn test_metrics_accuracy() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria::default();
    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    // Verify metrics are calculated correctly
    assert_eq!(
        universe.metrics.total_instruments,
        universe.instruments.len()
    );

    // Calculate expected averages
    let expected_avg_liquidity = universe
        .instruments
        .iter()
        .map(|i| i.liquidity_score)
        .sum::<f64>()
        / universe.instruments.len() as f64;

    let expected_avg_volatility = universe
        .instruments
        .iter()
        .map(|i| i.volatility)
        .sum::<f64>()
        / universe.instruments.len() as f64;

    let expected_avg_spread = universe
        .instruments
        .iter()
        .map(|i| i.spread_bps)
        .sum::<f64>()
        / universe.instruments.len() as f64;

    // Verify metrics match calculations
    assert!((universe.metrics.avg_liquidity_score - expected_avg_liquidity).abs() < 1e-10);
    assert!((universe.metrics.avg_volatility - expected_avg_volatility).abs() < 1e-10);
    assert!((universe.metrics.avg_spread_bps - expected_avg_spread).abs() < 1e-10);
}

#[tokio::test]
async fn test_asset_class_distribution() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria {
        asset_classes: vec![AssetClass::Futures, AssetClass::Currencies],
        regions: vec![Region::NorthAmerica, Region::Global],
        ..UniverseCriteria::default()
    };

    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    // Verify asset class distribution matches actual instruments
    let mut expected_distribution = std::collections::HashMap::new();
    for instrument in &universe.instruments {
        let key = format!("{:?}", instrument.asset_class);
        *expected_distribution.entry(key).or_insert(0) += 1;
    }

    assert_eq!(
        universe.metrics.asset_class_distribution,
        expected_distribution
    );
}

// ============================================================================
// REAL SYMBOL VALIDATION TESTS
// ============================================================================

#[tokio::test]
async fn test_real_symbols_es_nq() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria {
        min_liquidity: 0.90, // ES.FUT (0.95), NQ.FUT (0.92), CL.FUT (0.90)
        ..UniverseCriteria::default()
    };

    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    // Should include ES.FUT and NQ.FUT
    let symbols: std::collections::HashSet<_> = universe
        .instruments
        .iter()
        .map(|i| i.symbol.as_str())
        .collect();

    assert!(symbols.contains("ES.FUT"), "Should include ES.FUT");
    assert!(symbols.contains("NQ.FUT"), "Should include NQ.FUT");
}

#[tokio::test]
async fn test_real_symbols_all_available() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    // Very permissive criteria to get all symbols
    let criteria = UniverseCriteria {
        min_liquidity: 0.0,
        max_volatility: 1.0,
        asset_classes: vec![
            AssetClass::Futures,
            AssetClass::Currencies,
            AssetClass::Commodities,
        ],
        regions: vec![
            Region::NorthAmerica,
            Region::Global,
            Region::Europe,
            Region::Asia,
        ],
        min_market_cap: None,
        ..UniverseCriteria::default()
    };

    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    // Should have all 5 instruments: ES.FUT, NQ.FUT, ZN.FUT, 6E.FUT, CL.FUT
    let symbols: std::collections::HashSet<_> = universe
        .instruments
        .iter()
        .map(|i| i.symbol.as_str())
        .collect();

    assert_eq!(symbols.len(), 5, "Should have all 5 instruments");
    assert!(symbols.contains("ES.FUT"));
    assert!(symbols.contains("NQ.FUT"));
    assert!(symbols.contains("ZN.FUT"));
    assert!(symbols.contains("6E.FUT"));
    assert!(symbols.contains("CL.FUT"));
}

#[tokio::test]
async fn test_real_symbol_properties() {
    let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
        "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt".to_string()
    });

    let pool = sqlx::PgPool::connect(&database_url)
        .await
        .expect("Failed to connect to database");

    let selector = UniverseSelector::new(pool);

    let criteria = UniverseCriteria::default();
    let universe = selector
        .select_universe(criteria)
        .await
        .expect("Failed to select universe");

    // Verify properties of real symbols
    for instrument in &universe.instruments {
        // All should have valid properties
        assert!(instrument.liquidity_score > 0.0 && instrument.liquidity_score <= 1.0);
        assert!(instrument.volatility > 0.0 && instrument.volatility <= 1.0);
        assert!(instrument.avg_daily_volume > 0.0);
        assert!(instrument.spread_bps > 0.0);
        assert_eq!(instrument.exchange, "CME");
    }
}
