//! Test helper utilities and common functions

use chrono::Utc;
// Import from workspace dependencies properly
use common::{OrderSide, OrderStatus, OrderType, TimeInForce};
use rust_decimal::Decimal;
use std::collections::HashMap;
use trading_engine::trading_operations::TradingOrder;

/// Generate a simple test ID instead of using uuid
fn generate_test_id() -> String {
    use std::sync::atomic::{AtomicU64, Ordering};
    static COUNTER: AtomicU64 = AtomicU64::new(1);
    format!("TEST_{}", COUNTER.fetch_add(1, Ordering::SeqCst))
}

/// Create a test TradingOrder with all required fields
pub fn create_test_order(
    symbol: &str,
    side: OrderSide,
    quantity: Decimal,
    price: Decimal,
) -> TradingOrder {
    TradingOrder {
        id: generate_test_id().into(),
        symbol: symbol.to_string(),
        account_id: None,
        side,
        order_type: OrderType::Limit,
        quantity,
        price,
        time_in_force: TimeInForce::Day,
        metadata: HashMap::new(),
        created_at: Utc::now(),
        submitted_at: None,
        executed_at: None,
        status: OrderStatus::Created,
        fill_quantity: Decimal::ZERO,
        average_fill_price: None,
    }
}

/// Create test configuration with sensible defaults
pub fn create_test_config() -> TestConfig {
    TestConfig {
        initial_capital: Decimal::from(100_000),
        risk_free_rate: Decimal::new(2, 2), // 2%
        enable_logging: false,
    }
}

/// Test configuration structure
#[derive(Debug, Clone)]
pub struct TestConfig {
    /// Initial trading capital
    pub initial_capital: Decimal,
    /// Risk-free rate for calculations
    pub risk_free_rate: Decimal,
    /// Enable logging output
    pub enable_logging: bool,
}

impl Default for TestConfig {
    fn default() -> Self {
        create_test_config()
    }
}

/// Mock implementations for testing
pub mod mock_implementations {
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};
    use std::time::Duration;

    /// Mock performance monitor for testing
    #[derive(Debug, Clone)]
    pub struct MockPerformanceMonitor {
        stats: Arc<Mutex<PerformanceStats>>,
    }

    impl MockPerformanceMonitor {
        /// Create a new mock performance monitor
        pub fn new() -> Self {
            Self {
                stats: Arc::new(Mutex::new(PerformanceStats::default())),
            }
        }

        /// Record a single operation with its duration
        pub fn record_operation(&self, operation: &str, duration: Duration) {
            if let Ok(mut stats) = self.stats.lock() {
                stats.operations_count += 1;
                stats.total_duration += duration;
                stats.average_latency = stats.total_duration / stats.operations_count as u32;

                if duration > stats.max_latency {
                    stats.max_latency = duration;
                }
                if duration < stats.min_latency || stats.min_latency == Duration::ZERO {
                    stats.min_latency = duration;
                }

                stats
                    .operation_latencies
                    .insert(operation.to_string(), duration);
            }
        }

        /// Record a metric with a value and unit
        pub fn record_metric(
            &self,
            metric_name: &str,
            value: f64,
            unit: &str,
        ) -> Result<(), &'static str> {
            // Convert the metric value to a duration based on the unit
            let duration = match unit {
                "ns" => Duration::from_nanos(value as u64),
                "us" | "μs" => Duration::from_micros(value as u64),
                "ms" => Duration::from_millis(value as u64),
                "s" => Duration::from_secs(value as u64),
                // Non-time units - convert to a mock duration representation
                "ops/sec" | "orders/sec" | "ratio" | "ns/item" => {
                    // For non-time units, store as microseconds for simplicity
                    Duration::from_micros((value * 1000.0) as u64)
                },
                _ => Duration::from_nanos(1000), // Default fallback
            };

            self.record_operation(metric_name, duration);
            Ok(())
        }

        /// Get current performance statistics
        pub fn get_stats(&self) -> PerformanceStats {
            self.stats.lock().expect("Failed to lock stats").clone()
        }

        /// Reset all statistics to default values
        pub fn reset(&self) {
            if let Ok(mut stats) = self.stats.lock() {
                *stats = PerformanceStats::default();
            }
        }
    }

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

    /// Performance statistics for testing
    #[derive(Debug, Clone)]
    pub struct PerformanceStats {
        /// Total number of operations recorded
        pub operations_count: u64,
        /// Total duration of all operations
        pub total_duration: Duration,
        /// Average operation latency
        pub average_latency: Duration,
        /// Minimum operation latency
        pub min_latency: Duration,
        /// Maximum operation latency
        pub max_latency: Duration,
        /// Individual operation latencies by name
        pub operation_latencies: HashMap<String, Duration>,
    }

    impl Default for PerformanceStats {
        fn default() -> Self {
            Self {
                operations_count: 0,
                total_duration: Duration::ZERO,
                average_latency: Duration::ZERO,
                min_latency: Duration::ZERO,
                max_latency: Duration::ZERO,
                operation_latencies: HashMap::new(),
            }
        }
    }

    impl PerformanceStats {
        /// Calculate throughput in operations per second
        pub fn throughput_per_second(&self) -> f64 {
            if self.total_duration.as_secs_f64() > 0.0 {
                self.operations_count as f64 / self.total_duration.as_secs_f64()
            } else {
                0.0
            }
        }

        /// Get average latency in microseconds
        pub fn average_latency_micros(&self) -> u64 {
            self.average_latency.as_micros() as u64
        }

        /// Get maximum latency in microseconds
        pub fn max_latency_micros(&self) -> u64 {
            self.max_latency.as_micros() as u64
        }

        /// Get minimum latency in microseconds
        pub fn min_latency_micros(&self) -> u64 {
            self.min_latency.as_micros() as u64
        }
    }
}
