//! Test utilities for trading service tests
//!
//! Provides configurable test data fixtures and environment variable support
//! to avoid hardcoded production symbols in tests.

use std::env;

/// Default test symbols to use when environment variables are not set
pub const DEFAULT_TEST_SYMBOLS: &[&str] = &[
    "TEST_EQUITY_001",
    "TEST_EQUITY_002",
    "TEST_EQUITY_003",
    "TEST_EQUITY_004",
    "TEST_EQUITY_005",
];

/// Test configuration for symbols and other test data
#[derive(Debug, Clone)]
pub struct TestConfig {
    pub symbols: Vec<String>,
    pub default_account: String,
    pub default_strategy: String,
}

impl Default for TestConfig {
    fn default() -> Self {
        Self {
            symbols: DEFAULT_TEST_SYMBOLS.iter().map(|s| s.to_string()).collect(),
            default_account: "test_account".to_string(),
            default_strategy: "test_strategy".to_string(),
        }
    }
}

impl TestConfig {
    /// Create a new test configuration with environment variable overrides
    pub fn new() -> Self {
        let mut config = Self::default();

        // Override symbols from environment if provided
        if let Ok(symbols_env) = env::var("FOXHUNT_TEST_SYMBOLS") {
            config.symbols = symbols_env
                .split(',')
                .map(|s| s.trim().to_string())
                .filter(|s| !s.is_empty())
                .collect();
        }

        // Override account from environment if provided
        if let Ok(account_env) = env::var("FOXHUNT_TEST_ACCOUNT") {
            config.default_account = account_env;
        }

        // Override strategy from environment if provided
        if let Ok(strategy_env) = env::var("FOXHUNT_TEST_STRATEGY") {
            config.default_strategy = strategy_env;
        }

        config
    }

    /// Get primary test symbol
    pub fn primary_symbol(&self) -> &str {
        &self.symbols[0]
    }

    /// Get secondary test symbol
    pub fn secondary_symbol(&self) -> &str {
        &self.symbols[1]
    }

    /// Get tertiary test symbol
    pub fn tertiary_symbol(&self) -> &str {
        &self.symbols[2]
    }

    /// Get all test symbols
    pub fn all_symbols(&self) -> &[String] {
        &self.symbols
    }

    /// Get a subset of symbols for testing
    pub fn symbol_subset(&self, count: usize) -> Vec<String> {
        self.symbols.iter().take(count).cloned().collect()
    }
}

/// Test fixtures for consistent test data
pub struct TestFixtures {
    pub config: TestConfig,
}

impl Default for TestFixtures {
    fn default() -> Self {
        Self::new()
    }
}

impl TestFixtures {
    /// Create new test fixtures
    pub fn new() -> Self {
        Self {
            config: TestConfig::new(),
        }
    }

    /// Create a test order ID
    pub fn test_order_id(&self, suffix: &str) -> String {
        format!("test_order_{}", suffix)
    }

    /// Create test prices for a given symbol
    pub fn test_prices(&self, symbol: &str) -> (f64, f64) {
        // Generate deterministic but varied prices based on symbol hash
        let hash = symbol.chars().map(|c| c as u32).sum::<u32>();
        let base_price = 100.0 + (hash % 100) as f64;
        (base_price, base_price + 5.0)
    }

    /// Create test quantities
    pub fn test_quantities(&self) -> (f64, f64) {
        (100.0, 50.0)
    }
}

/// Macro to get test config for consistent usage across tests
#[macro_export]
macro_rules! test_config {
    () => {
        $crate::test_utils::TestConfig::new()
    };
}

/// Macro to get test fixtures for consistent usage across tests
#[macro_export]
macro_rules! test_fixtures {
    () => {
        $crate::test_utils::TestFixtures::new()
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_creation() {
        let config = TestConfig::new();
        assert!(!config.symbols.is_empty());
        assert!(!config.default_account.is_empty());
        assert!(!config.default_strategy.is_empty());
    }

    #[test]
    fn test_symbol_access() {
        let config = TestConfig::new();
        assert_eq!(config.primary_symbol(), config.symbols[0]);
        assert_eq!(config.secondary_symbol(), config.symbols[1]);
        assert_eq!(config.tertiary_symbol(), config.symbols[2]);
    }

    #[test]
    fn test_fixtures_creation() {
        let fixtures = TestFixtures::new();
        let order_id = fixtures.test_order_id("123");
        assert!(order_id.contains("test_order_123"));

        let (price1, price2) = fixtures.test_prices("TEST_SYMBOL");
        assert!(price1 > 0.0);
        assert!(price2 > price1);
    }

    #[test]
    fn test_symbol_subset() {
        let config = TestConfig::new();
        let subset = config.symbol_subset(2);
        assert_eq!(subset.len(), 2);
        assert_eq!(subset[0], config.symbols[0]);
        assert_eq!(subset[1], config.symbols[1]);
    }
}
