//! Strategy testing framework for backtesting
//!
//! Provides infrastructure for executing trading strategies against historical data,
//! managing positions, tracking performance, and handling risk management.

// Import everything async_trait needs - use fully qualified paths to avoid shadowing
use std::{
    collections::{HashMap, VecDeque},
    sync::Arc,
};

use anyhow::{Context, Result};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use common::Order;
use common::OrderId;
use common::OrderSide;
use common::OrderStatus;
use common::OrderType;
use common::Position;
use common::Price;
use common::Quantity;
use common::Symbol;
use common::TimeInForce;
use dashmap::DashMap;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use serde_json;
use tokio::sync::RwLock;
use tracing::{error, info};
use trading_engine::types::events::MarketEvent;
use uuid::Uuid;
// TECHNICAL DEBT ELIMINATED - Use String and DateTime<Utc> directly
use crate::replay_engine::{MarketReplay, ReplayEvent};
/// Trading strategy trait that backtesting strategies must implement
#[async_trait(?Send)]
pub trait Strategy: Send + Sync {
    /// Strategy name for identification
    fn name(&self) -> &str;

    /// Initialize strategy with initial capital and configuration
    async fn initialize(&mut self, initial_capital: Decimal, config: StrategyConfig) -> Result<()>;

    /// Process market event and generate trading signals
    async fn on_market_event(
        &mut self,
        event: &MarketEvent,
        context: &StrategyContext,
    ) -> Result<Vec<TradingSignal>>;

    /// Handle order execution updates
    async fn on_order_update(&mut self, order: &Order, context: &StrategyContext) -> Result<()>;

    /// Handle position updates
    async fn on_position_update(
        &mut self,
        position: &Position,
        context: &StrategyContext,
    ) -> Result<()>;

    /// Strategy cleanup and final calculations
    async fn finalize(&mut self, context: &StrategyContext) -> Result<StrategyResult>;

    /// Get current strategy state for debugging
    async fn get_state(&self) -> Result<serde_json::Value>;
}

/// Strategy configuration parameters
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategyConfig {
    /// Maximum position size per symbol
    pub max_position_size: Decimal,
    /// Risk per trade as percentage of capital
    pub risk_per_trade: Decimal,
    /// Maximum number of open positions
    pub max_open_positions: u32,
    /// Stop loss percentage
    pub stop_loss_pct: Option<Decimal>,
    /// Take profit percentage
    pub take_profit_pct: Option<Decimal>,
    /// Strategy-specific parameters
    pub parameters: HashMap<String, serde_json::Value>,
    /// Enable position sizing
    pub position_sizing_enabled: bool,
    /// Commission rate per trade
    pub commission_rate: Decimal,
    /// Slippage factor
    pub slippage_factor: Decimal,
}

impl Default for StrategyConfig {
    fn default() -> Self {
        Self {
            max_position_size: Decimal::from(100000),
            risk_per_trade: Decimal::new(2, 2), // 2%
            max_open_positions: 10,
            stop_loss_pct: Some(Decimal::new(5, 2)),    // 5%
            take_profit_pct: Some(Decimal::new(10, 2)), // 10%
            parameters: HashMap::new(),
            position_sizing_enabled: true,
            commission_rate: Decimal::new(1, 4), // 0.01%
            slippage_factor: Decimal::new(5, 5), // 0.005%
        }
    }
}

/// Context provided to strategy during execution
#[derive(Debug, Clone)]
pub struct StrategyContext {
    /// Current timestamp
    pub current_time: DateTime<Utc>,
    /// Current account balance
    pub account_balance: Decimal,
    /// Available buying power
    pub buying_power: Decimal,
    /// Current positions
    pub positions: HashMap<Symbol, Position>,
    /// Open orders
    pub open_orders: HashMap<OrderId, Order>,
    /// Current market prices
    pub market_prices: HashMap<Symbol, Price>,
    /// Performance metrics
    pub performance: PerformanceMetrics,
}

/// Trading signal generated by strategy
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TradingSignal {
    /// Symbol to trade
    pub symbol: Symbol,
    /// Signal type
    pub signal_type: SignalType,
    /// Suggested quantity
    pub quantity: Quantity,
    /// Target price (if limit order)
    pub target_price: Option<Price>,
    /// Stop loss price
    pub stop_loss: Option<Price>,
    /// Take profit price
    pub take_profit: Option<Price>,
    /// Signal confidence (0.0 - 1.0)
    pub confidence: Decimal,
    /// Additional metadata
    pub metadata: HashMap<String, serde_json::Value>,
}

/// Types of trading signals
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SignalType {
    Buy,
    Sell,
    Short,
    Cover,
    CloseLong,
    CloseShort,
    CloseAll,
}

/// Strategy execution result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategyResult {
    /// Strategy name
    pub strategy_name: String,
    /// Total return
    pub total_return: Decimal,
    /// Annualized return
    pub annualized_return: Decimal,
    /// Maximum drawdown
    pub max_drawdown: Decimal,
    /// Sharpe ratio
    pub sharpe_ratio: Decimal,
    /// Number of trades
    pub total_trades: u64,
    /// Win rate
    pub win_rate: Decimal,
    /// Average trade return
    pub avg_trade_return: Decimal,
    /// Final portfolio value
    pub final_value: Decimal,
    /// Detailed trade history
    pub trades: Vec<TradeRecord>,
    /// Performance timeline
    pub performance_timeline: Vec<PerformanceSnapshot>,
}

/// Individual trade record
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TradeRecord {
    /// Trade ID
    pub trade_id: String,
    /// Symbol traded
    pub symbol: Symbol,
    /// Trade side
    pub side: OrderSide,
    /// Entry price
    pub entry_price: Price,
    /// Exit price
    pub exit_price: Price,
    /// Quantity traded
    pub quantity: Quantity,
    /// Entry timestamp
    pub entry_time: DateTime<Utc>,
    /// Exit timestamp
    pub exit_time: DateTime<Utc>,
    /// Profit/loss
    pub pnl: Decimal,
    /// Return percentage
    pub return_pct: Decimal,
    /// Commission paid
    pub commission: Decimal,
}

/// Performance snapshot at a point in time
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceSnapshot {
    /// Timestamp
    pub timestamp: DateTime<Utc>,
    /// Portfolio value
    pub portfolio_value: Decimal,
    /// Cash balance
    pub cash_balance: Decimal,
    /// Unrealized PnL
    pub unrealized_pnl: Decimal,
    /// Realized PnL
    pub realized_pnl: Decimal,
    /// Number of open positions
    pub open_positions: u32,
    /// Current drawdown
    pub drawdown: Decimal,
}

/// Performance metrics tracked during execution
#[derive(Debug, Clone, Default)]
pub struct PerformanceMetrics {
    /// Total realized PnL
    pub total_realized_pnl: Decimal,
    /// Total unrealized PnL
    pub total_unrealized_pnl: Decimal,
    /// Peak portfolio value
    pub peak_value: Decimal,
    /// Current drawdown
    pub current_drawdown: Decimal,
    /// Maximum drawdown
    pub max_drawdown: Decimal,
    /// Total trades executed
    pub total_trades: u64,
    /// Winning trades
    pub winning_trades: u64,
    /// Total commission paid
    pub total_commission: Decimal,
    /// Returns history
    pub daily_returns: VecDeque<Decimal>,
}

/// Strategy tester engine
pub struct StrategyTester {
    /// Strategy being tested
    strategy: Box<dyn Strategy>,
    /// Strategy configuration
    config: StrategyConfig,
    /// Market replay engine
    market_replay: Arc<MarketReplay>,
    /// Current account state
    account: Arc<RwLock<Account>>,
    /// Order management system
    order_manager: Arc<OrderManager>,
    /// Position tracker
    position_tracker: Arc<PositionTracker>,
    /// Performance tracker
    performance_tracker: Arc<RwLock<PerformanceTracker>>,
    /// Current market data
    market_data: Arc<DashMap<Symbol, MarketEvent>>,
}

/// Account state for backtesting
#[derive(Debug, Clone)]
pub struct Account {
    /// Initial capital
    pub initial_capital: Decimal,
    /// Current cash balance
    pub cash_balance: Decimal,
    /// Total portfolio value
    pub portfolio_value: Decimal,
    /// Account creation time
    pub created_at: DateTime<Utc>,
    /// Last update time
    pub last_updated: DateTime<Utc>,
}

/// Order management for backtesting
pub struct OrderManager {
    /// Open orders
    orders: DashMap<OrderId, Order>,
    /// Next order ID
    next_order_id: std::sync::atomic::AtomicU64,
}

/// Position tracking for backtesting
pub struct PositionTracker {
    /// Current positions
    positions: DashMap<Symbol, Position>,
    /// Position history
    position_history: RwLock<Vec<Position>>,
    /// Trade records
    trade_records: RwLock<Vec<TradeRecord>>,
}

/// Performance tracking
pub struct PerformanceTracker {
    /// Performance metrics
    metrics: PerformanceMetrics,
    /// Performance snapshots
    snapshots: Vec<PerformanceSnapshot>,
    /// Last snapshot time
    last_snapshot: Option<DateTime<Utc>>,
}

impl StrategyTester {
    /// Create new strategy tester
    pub fn new(
        strategy: Box<dyn Strategy>,
        config: StrategyConfig,
        market_replay: Arc<MarketReplay>,
        initial_capital: Decimal,
    ) -> Self {
        let account = Account {
            initial_capital,
            cash_balance: initial_capital,
            portfolio_value: initial_capital,
            created_at: Utc::now(),
            last_updated: Utc::now(),
        };

        Self {
            strategy,
            config,
            market_replay,
            account: Arc::new(RwLock::new(account)),
            order_manager: Arc::new(OrderManager::new()),
            position_tracker: Arc::new(PositionTracker::new()),
            performance_tracker: Arc::new(RwLock::new(PerformanceTracker::new())),
            market_data: Arc::new(DashMap::new()),
        }
    }

    /// Run the strategy test
    pub async fn run_test(&mut self) -> Result<StrategyResult> {
        info!("Starting strategy test for: {}", self.strategy.name());

        // Initialize strategy
        self.strategy
            .initialize(
                self.account.read().await.initial_capital,
                self.config.clone(),
            )
            .await?;

        // Get market data receiver
        let mut event_receiver = self
            .market_replay
            .take_receiver()
            .await
            .context("Failed to get market data receiver")?;

        // Start market replay
        let replay_handle = {
            let replay = Arc::clone(&self.market_replay);
            tokio::spawn(async move {
                if let Err(e) = replay.start_replay().await {
                    error!("Market replay failed: {}", e);
                }
            })
        };

        // Process market events
        while let Some(replay_event) = event_receiver.recv().await {
            if let Err(e) = self.process_market_event(replay_event).await {
                error!("Failed to process market event: {}", e);
            }
        }

        // Wait for replay to complete
        replay_handle.await?;

        // Finalize strategy and generate results
        let context = self.build_strategy_context().await?;
        let result = self.strategy.finalize(&context).await?;

        info!(
            "Strategy test completed. Total return: {:.2}%",
            result.total_return * Decimal::from(100)
        );

        Ok(result)
    }

    /// Process a single market event
    async fn process_market_event(&mut self, replay_event: ReplayEvent) -> Result<()> {
        let event = &replay_event.event;

        // Update market data
        self.update_market_data(event).await;

        // Update account and positions with current market prices
        self.update_valuations().await?;

        // Process pending orders
        self.process_pending_orders().await?;

        // Build strategy context
        let context = self.build_strategy_context().await?;

        // Get trading signals from strategy
        let signals = self.strategy.on_market_event(event, &context).await?;

        // Execute trading signals
        for signal in signals {
            self.execute_trading_signal(signal).await?;
        }

        // Take performance snapshot periodically
        self.take_performance_snapshot(&context).await?;

        Ok(())
    }

    /// Update market data cache
    async fn update_market_data(&self, event: &MarketEvent) {
        let symbol = match event {
            MarketEvent::Trade { symbol, .. } => symbol,
            MarketEvent::Quote { symbol, .. } => symbol,
            MarketEvent::OrderBookUpdate { symbol, .. } => symbol,
            MarketEvent::Bar { symbol, .. } => symbol,
            MarketEvent::OrderBook { symbol, .. } => symbol,
            MarketEvent::Sentiment { .. } => return, // Skip sentiment events for now
            MarketEvent::Control { .. } => return,   // Skip control events for now
        };

        self.market_data.insert(symbol.clone(), event.clone());
    }

    /// Update portfolio valuations
    async fn update_valuations(&self) -> Result<()> {
        let mut account = self.account.write().await;
        let positions = self.position_tracker.get_all_positions().await;

        let mut total_value = account.cash_balance;

        for (symbol, position) in positions {
            if let Some(market_event) = self.market_data.get(&symbol) {
                let current_price = self.extract_price_from_event(&market_event)?;
                let position_decimal = position.quantity;
                let price_decimal = current_price.to_decimal().unwrap_or(Decimal::ZERO);
                let position_value = position_decimal * price_decimal;

                if position_decimal >= Decimal::ZERO {
                    total_value += position_value;
                } else {
                    // Short position
                    total_value -= position_value;
                }
            }
        }

        account.portfolio_value = total_value;
        account.last_updated = Utc::now();

        Ok(())
    }

    /// Process pending orders for execution
    async fn process_pending_orders(&mut self) -> Result<()> {
        let pending_orders = self.order_manager.get_pending_orders().await;

        for order in pending_orders {
            // Extract the current price first to avoid borrowing conflicts
            let current_price = if let Some(market_event) = self.market_data.get(&order.symbol) {
                self.extract_price_from_event(&market_event)?
            } else {
                continue; // Skip this order if no market data available
            };

            // Now check if we should execute and execute if needed
            if self.should_execute_order(&order, current_price) {
                self.execute_order(order).await?;
            }
        }

        Ok(())
    }

    /// Check if order should be executed
    fn should_execute_order(&self, order: &Order, current_price: Price) -> bool {
        match order.order_type {
            OrderType::Market => true,
            OrderType::Iceberg => {
                // For backtesting, treat Iceberg orders as market orders
                true
            },
            OrderType::Limit => {
                if let Some(order_price) = order.price {
                    match order.side {
                        OrderSide::Buy => current_price <= order_price,
                        OrderSide::Sell => current_price >= order_price,
                    }
                } else {
                    false
                }
            },
            OrderType::Stop => {
                if let Some(order_price) = order.price {
                    match order.side {
                        OrderSide::Buy => current_price >= order_price,
                        OrderSide::Sell => current_price <= order_price,
                    }
                } else {
                    false
                }
            },
            OrderType::StopLimit => {
                // Simplified logic - would need stop price tracking
                if let Some(order_price) = order.price {
                    match order.side {
                        OrderSide::Buy => current_price >= order_price,
                        OrderSide::Sell => current_price <= order_price,
                    }
                } else {
                    false
                }
            },
            OrderType::TrailingStop => {
                // For backtesting, treat as stop order
                if let Some(order_price) = order.price {
                    match order.side {
                        OrderSide::Buy => current_price >= order_price,
                        OrderSide::Sell => current_price <= order_price,
                    }
                } else {
                    false
                }
            },
            OrderType::Hidden => {
                // For backtesting, treat as market order
                true
            },
            _ => {
                // Default case for any other order types
                false
            },
        }
    }

    /// Execute an order
    async fn execute_order(&mut self, mut order: Order) -> Result<()> {
        let current_price = if let Some(market_event) = self.market_data.get(&order.symbol) {
            self.extract_price_from_event(&market_event)?
        } else {
            return Err(anyhow::anyhow!(
                "No market data for symbol: {}",
                order.symbol
            ));
        };

        // Apply slippage
        let execution_price = self.apply_slippage(current_price, &order);

        // Calculate commission
        let commission = self.calculate_commission(&order, execution_price);

        // Update order
        order.status = OrderStatus::Filled;
        order.filled_quantity = order.quantity;
        order.average_price = Some(execution_price);

        // Update account
        let mut account = self.account.write().await;
        let trade_value = order.quantity.to_decimal().unwrap_or(Decimal::ZERO)
            * execution_price.to_decimal().unwrap_or(Decimal::ZERO);

        match order.side {
            OrderSide::Buy => {
                account.cash_balance -= trade_value + commission;
            },
            OrderSide::Sell => {
                account.cash_balance += trade_value - commission;
            },
        }

        // Update positions
        self.position_tracker
            .update_position(&order.symbol, &order, execution_price)
            .await?;

        // Record trade
        self.position_tracker
            .record_trade(&order, execution_price, commission)
            .await;

        // Notify strategy of order update
        let context = self.build_strategy_context().await?;
        self.strategy.on_order_update(&order, &context).await?;

        info!(
            "Executed order: {:?} {} {} @ {} (commission: {})",
            order.side, order.quantity, order.symbol, execution_price, commission
        );

        Ok(())
    }

    /// Execute a trading signal
    async fn execute_trading_signal(&mut self, signal: TradingSignal) -> Result<()> {
        let order = self.convert_signal_to_order(signal).await?;
        self.order_manager.place_order(order).await?;
        Ok(())
    }

    /// Convert trading signal to order
    async fn convert_signal_to_order(&self, signal: TradingSignal) -> Result<Order> {
        let order_id = self.order_manager.generate_order_id();

        let (side, order_type, price) = match signal.signal_type {
            SignalType::Buy => (OrderSide::Buy, OrderType::Market, Price::zero()),
            SignalType::Sell => (OrderSide::Sell, OrderType::Market, Price::zero()),
            SignalType::Short => (OrderSide::Sell, OrderType::Market, Price::zero()),
            SignalType::Cover => (OrderSide::Buy, OrderType::Market, Price::zero()),
            _ => {
                return Err(anyhow::anyhow!(
                    "Unsupported signal type: {:?}",
                    signal.signal_type
                ))
            },
        };

        Ok(Order {
            id: order_id.clone(),
            client_order_id: Some(format!("client_{}", Uuid::new_v4())),
            broker_order_id: None,
            account_id: Some("default".to_string()),
            symbol: signal.symbol,
            side,
            order_type,
            status: OrderStatus::Pending,
            time_in_force: TimeInForce::Day,
            quantity: signal.quantity,
            price: Some(price),
            stop_price: None,
            filled_quantity: Quantity::zero(),
            remaining_quantity: signal.quantity,
            average_price: None,
            avg_fill_price: None,
            average_fill_price: None,
            exchange_order_id: None,
            parent_id: None,
            execution_algorithm: None,
            execution_params: serde_json::json!({}),
            stop_loss: None,
            take_profit: None,
            created_at: common::HftTimestamp::now_or_zero(),
            updated_at: None,
            expires_at: None,
            metadata: serde_json::json!({}),
        })
    }

    /// Apply slippage to execution price
    fn apply_slippage(&self, price: Price, order: &Order) -> Price {
        let slippage = price.to_decimal().unwrap_or(Decimal::ZERO) * self.config.slippage_factor;
        match order.side {
            OrderSide::Buy => Price::from_f64(
                (price.to_decimal().unwrap_or(Decimal::ZERO) + slippage)
                    .try_into()
                    .unwrap_or(0.0),
            )
            .unwrap_or(Price::zero()),
            OrderSide::Sell => Price::from_f64(
                (price.to_decimal().unwrap_or(Decimal::ZERO) - slippage)
                    .try_into()
                    .unwrap_or(0.0),
            )
            .unwrap_or(Price::zero()),
        }
    }

    /// Calculate commission for trade
    fn calculate_commission(&self, order: &Order, price: Price) -> Decimal {
        let trade_value = order.quantity.to_decimal().unwrap_or(Decimal::ZERO)
            * price.to_decimal().unwrap_or(Decimal::ZERO);
        trade_value * self.config.commission_rate
    }

    /// Extract price from market event
    fn extract_price_from_event(&self, event: &MarketEvent) -> Result<Price> {
        match event {
            MarketEvent::Trade { price, .. } => Ok(*price),
            MarketEvent::Quote {
                bid_price,
                ask_price,
                ..
            } => {
                let avg_price = (bid_price.to_decimal().unwrap_or(Decimal::ZERO)
                    + ask_price.to_decimal().unwrap_or(Decimal::ZERO))
                    / Decimal::from(2);
                Ok(Price::from_f64(avg_price.try_into().unwrap_or(0.0)).unwrap_or(Price::ZERO))
            },
            MarketEvent::Bar { close, .. } => Ok(*close),
            _ => Err(anyhow::anyhow!(
                "Cannot extract price from event: {:?}",
                event
            )),
        }
    }

    /// Build strategy context
    async fn build_strategy_context(&self) -> Result<StrategyContext> {
        let account = self.account.read().await;
        let positions = self.position_tracker.get_all_positions().await;
        let open_orders = self.order_manager.get_all_orders().await;
        let performance = self.performance_tracker.read().await.metrics.clone();

        let mut market_prices = HashMap::new();
        for item in self.market_data.iter() {
            let symbol = item.key();
            let event = item.value();
            if let Ok(price) = self.extract_price_from_event(event) {
                market_prices.insert(symbol.clone(), price);
            }
        }

        Ok(StrategyContext {
            current_time: Utc::now(),
            account_balance: account.cash_balance,
            buying_power: account.cash_balance, // Simplified
            positions,
            open_orders,
            market_prices,
            performance,
        })
    }

    /// Take performance snapshot
    async fn take_performance_snapshot(&self, context: &StrategyContext) -> Result<()> {
        let mut tracker = self.performance_tracker.write().await;

        let snapshot = PerformanceSnapshot {
            timestamp: context.current_time,
            portfolio_value: context.account_balance,
            cash_balance: context.account_balance,
            unrealized_pnl: context.performance.total_unrealized_pnl,
            realized_pnl: context.performance.total_realized_pnl,
            open_positions: context.positions.len() as u32,
            drawdown: context.performance.current_drawdown,
        };

        tracker.snapshots.push(snapshot);
        tracker.last_snapshot = Some(context.current_time);

        Ok(())
    }
}

impl OrderManager {
    pub fn new() -> Self {
        Self {
            orders: DashMap::new(),
            next_order_id: std::sync::atomic::AtomicU64::new(1),
        }
    }

    pub fn generate_order_id(&self) -> OrderId {
        format!(
            "order_{}",
            self.next_order_id
                .fetch_add(1, std::sync::atomic::Ordering::Relaxed)
        )
        .into()
    }

    pub async fn place_order(&self, order: Order) -> Result<()> {
        let order_id = order.id.clone();
        self.orders.insert(order_id, order);
        Ok(())
    }

    pub async fn get_pending_orders(&self) -> Vec<Order> {
        self.orders
            .iter()
            .filter(|entry| entry.value().status == OrderStatus::Pending)
            .map(|entry| entry.value().clone())
            .collect()
    }

    pub async fn get_all_orders(&self) -> HashMap<OrderId, Order> {
        self.orders
            .iter()
            .map(|entry| (entry.key().clone(), entry.value().clone()))
            .collect()
    }
}

impl PositionTracker {
    pub fn new() -> Self {
        Self {
            positions: DashMap::new(),
            position_history: RwLock::new(Vec::new()),
            trade_records: RwLock::new(Vec::new()),
        }
    }

    pub async fn get_all_positions(&self) -> HashMap<Symbol, Position> {
        self.positions
            .iter()
            .map(|entry| (entry.key().clone(), entry.value().clone()))
            .collect()
    }

    /// Update position accounting for a filled order.
    ///
    /// Handles opening new positions, adding to existing ones, reducing positions,
    /// closing positions (generating a TradeRecord with realized PnL), and flipping
    /// from long to short or vice-versa.
    pub async fn update_position(
        &self,
        symbol: &Symbol,
        order: &Order,
        execution_price: Price,
    ) -> Result<()> {
        let exec_price_dec = execution_price.to_decimal().unwrap_or(Decimal::ZERO);
        let order_qty_dec = order.quantity.to_decimal().unwrap_or(Decimal::ZERO);

        // Signed fill quantity: positive for Buy, negative for Sell
        let signed_fill_qty = match order.side {
            OrderSide::Buy => order_qty_dec,
            OrderSide::Sell => -order_qty_dec,
        };

        let now = Utc::now();

        if let Some(mut pos_ref) = self.positions.get_mut(symbol) {
            let old_qty = pos_ref.quantity;
            let old_avg = pos_ref.avg_price;
            let new_qty = old_qty + signed_fill_qty;

            // Determine if this fill reduces / closes the position
            // A reduction happens when old_qty and signed_fill_qty have opposite signs
            let is_reducing = (old_qty > Decimal::ZERO && signed_fill_qty < Decimal::ZERO)
                || (old_qty < Decimal::ZERO && signed_fill_qty > Decimal::ZERO);

            if is_reducing {
                // Quantity being closed is the smaller of |old_qty| and |signed_fill_qty|
                let closed_qty = old_qty.abs().min(order_qty_dec);
                // PnL: for a long close: (exit - entry) * qty
                //       for a short close: (entry - exit) * qty
                let pnl = if old_qty > Decimal::ZERO {
                    (exec_price_dec - old_avg) * closed_qty
                } else {
                    (old_avg - exec_price_dec) * closed_qty
                };

                let entry_side = if old_qty > Decimal::ZERO {
                    OrderSide::Buy
                } else {
                    OrderSide::Sell
                };

                // Record the round-trip trade
                let trade = TradeRecord {
                    trade_id: Uuid::new_v4().to_string(),
                    symbol: symbol.clone(),
                    side: entry_side,
                    entry_price: Price::from_decimal(old_avg),
                    exit_price: execution_price,
                    quantity: Quantity::from_f64(
                        closed_qty.try_into().unwrap_or(0.0),
                    )
                    .unwrap_or(Quantity::ZERO),
                    entry_time: pos_ref.created_at,
                    exit_time: now,
                    pnl,
                    return_pct: if old_avg != Decimal::ZERO {
                        pnl / (old_avg * closed_qty) * Decimal::from(100)
                    } else {
                        Decimal::ZERO
                    },
                    commission: Decimal::ZERO, // Commission tracked separately in record_trade
                };

                let mut records = self.trade_records.write().await;
                records.push(trade);

                if new_qty == Decimal::ZERO {
                    // Position fully closed -- archive and remove
                    let closed_pos = pos_ref.clone();
                    drop(pos_ref);
                    let mut history = self.position_history.write().await;
                    history.push(closed_pos);
                    self.positions.remove(symbol);
                } else if (new_qty > Decimal::ZERO) != (old_qty > Decimal::ZERO) {
                    // Position flipped direction -- close old fully, open new with remainder
                    let remainder_qty = new_qty.abs();

                    // Archive the closed position
                    let closed_pos = pos_ref.clone();
                    // Update to the new flipped position
                    pos_ref.quantity = new_qty;
                    pos_ref.avg_price = exec_price_dec;
                    pos_ref.avg_cost = exec_price_dec;
                    pos_ref.average_price = exec_price_dec;
                    pos_ref.basis = remainder_qty * exec_price_dec;
                    pos_ref.unrealized_pnl = Decimal::ZERO;
                    pos_ref.realized_pnl += pnl;
                    pos_ref.updated_at = now;
                    pos_ref.last_updated = now;

                    drop(pos_ref);
                    let mut history = self.position_history.write().await;
                    history.push(closed_pos);
                } else {
                    // Partial reduction, same direction
                    pos_ref.quantity = new_qty;
                    pos_ref.realized_pnl += pnl;
                    pos_ref.updated_at = now;
                    pos_ref.last_updated = now;
                }
            } else {
                // Adding to existing position (same direction) -- compute weighted avg price
                let total_cost = old_avg * old_qty.abs() + exec_price_dec * order_qty_dec;
                let total_qty = old_qty.abs() + order_qty_dec;
                let new_avg = if total_qty != Decimal::ZERO {
                    total_cost / total_qty
                } else {
                    exec_price_dec
                };

                pos_ref.quantity = new_qty;
                pos_ref.avg_price = new_avg;
                pos_ref.avg_cost = new_avg;
                pos_ref.average_price = new_avg;
                pos_ref.basis = total_qty * new_avg;
                pos_ref.updated_at = now;
                pos_ref.last_updated = now;
            }
        } else {
            // No existing position -- open a new one
            let pos = Position::new(symbol.as_str().to_owned(), signed_fill_qty, exec_price_dec);
            self.positions.insert(symbol.clone(), pos);
        }

        Ok(())
    }

    /// Record a trade fill for audit / reporting.
    ///
    /// This creates a TradeRecord from the raw fill data and appends it to the
    /// internal trade log. For round-trip PnL records, see `update_position`.
    pub async fn record_trade(
        &self,
        order: &Order,
        execution_price: Price,
        commission: Decimal,
    ) {
        let now = Utc::now();
        let trade = TradeRecord {
            trade_id: Uuid::new_v4().to_string(),
            symbol: order.symbol.clone(),
            side: order.side.clone(),
            entry_price: execution_price,
            exit_price: execution_price,
            quantity: order.quantity,
            entry_time: order.created_at.to_datetime(),
            exit_time: now,
            pnl: Decimal::ZERO, // Raw fill; PnL computed in update_position
            return_pct: Decimal::ZERO,
            commission,
        };

        let mut records = self.trade_records.write().await;
        records.push(trade);
    }

    /// Get a snapshot of all recorded trades.
    pub async fn get_trades(&self) -> Vec<TradeRecord> {
        let records = self.trade_records.read().await;
        records.clone()
    }

    /// Sum of realized PnL across all recorded round-trip trades.
    pub async fn get_realized_pnl(&self) -> Decimal {
        let records = self.trade_records.read().await;
        records.iter().map(|t| t.pnl).sum()
    }
}

impl PerformanceTracker {
    pub fn new() -> Self {
        Self {
            metrics: PerformanceMetrics::default(),
            snapshots: Vec::new(),
            last_snapshot: None,
        }
    }
}

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

    struct TestStrategy {
        name: String,
    }

    #[async_trait(?Send)]
    impl Strategy for TestStrategy {
        fn name(&self) -> &str {
            &self.name
        }

        async fn initialize(
            &mut self,
            _initial_capital: Decimal,
            _config: StrategyConfig,
        ) -> Result<()> {
            Ok(())
        }

        async fn on_market_event(
            &mut self,
            _event: &MarketEvent,
            _context: &StrategyContext,
        ) -> Result<Vec<TradingSignal>> {
            Ok(vec![])
        }

        async fn on_order_update(
            &mut self,
            _order: &Order,
            _context: &StrategyContext,
        ) -> Result<()> {
            Ok(())
        }

        async fn on_position_update(
            &mut self,
            _position: &Position,
            _context: &StrategyContext,
        ) -> Result<()> {
            Ok(())
        }

        async fn finalize(&mut self, _context: &StrategyContext) -> Result<StrategyResult> {
            Ok(StrategyResult {
                strategy_name: self.name.clone(),
                total_return: Decimal::ZERO,
                annualized_return: Decimal::ZERO,
                max_drawdown: Decimal::ZERO,
                sharpe_ratio: Decimal::ZERO,
                total_trades: 0,
                win_rate: Decimal::ZERO,
                avg_trade_return: Decimal::ZERO,
                final_value: Decimal::from(100000),
                trades: vec![],
                performance_timeline: vec![],
            })
        }

        async fn get_state(&self) -> Result<serde_json::Value> {
            Ok(serde_json::json!({"name": self.name}))
        }
    }

    #[tokio::test]
    async fn test_strategy_tester_creation() {
        use crate::replay_engine::{MarketReplay, ReplayConfig};

        let strategy = Box::new(TestStrategy {
            name: "test_strategy".to_string(),
        });

        let config = StrategyConfig::default();
        let replay_config = ReplayConfig::default();
        let market_replay = Arc::new(MarketReplay::new(replay_config));
        let initial_capital = Decimal::from(100000);

        let tester = StrategyTester::new(strategy, config, market_replay, initial_capital);
        assert_eq!(tester.strategy.name(), "test_strategy");
    }

    /// Helper: build a minimal Order for testing position tracker logic.
    fn make_test_order(symbol: &str, side: OrderSide, qty_f64: f64) -> Order {
        Order {
            id: format!("test_{}", Uuid::new_v4()).into(),
            client_order_id: None,
            broker_order_id: None,
            account_id: None,
            symbol: Symbol::from(symbol),
            side,
            order_type: OrderType::Market,
            status: OrderStatus::Filled,
            time_in_force: TimeInForce::Day,
            quantity: Quantity::from_f64(qty_f64).unwrap_or(Quantity::ZERO),
            price: None,
            stop_price: None,
            filled_quantity: Quantity::from_f64(qty_f64).unwrap_or(Quantity::ZERO),
            remaining_quantity: Quantity::ZERO,
            average_price: None,
            avg_fill_price: None,
            average_fill_price: None,
            exchange_order_id: None,
            parent_id: None,
            execution_algorithm: None,
            execution_params: serde_json::json!({}),
            stop_loss: None,
            take_profit: None,
            created_at: common::HftTimestamp::now_or_zero(),
            updated_at: None,
            expires_at: None,
            metadata: serde_json::json!({}),
        }
    }

    #[tokio::test]
    async fn test_position_tracker_records_trade() {
        let tracker = PositionTracker::new();
        let order = make_test_order("AAPL", OrderSide::Buy, 10.0);
        let price = Price::from_f64(150.0).unwrap();
        let commission = Decimal::new(15, 1); // 1.5

        tracker.record_trade(&order, price, commission).await;

        let trades = tracker.get_trades().await;
        assert_eq!(trades.len(), 1);
        let trade = &trades[0];
        assert_eq!(trade.symbol, Symbol::from("AAPL"));
        assert_eq!(trade.side, OrderSide::Buy);
        assert_eq!(trade.commission, Decimal::new(15, 1));
        assert_eq!(trade.quantity, order.quantity);
    }

    #[tokio::test]
    async fn test_position_tracker_update_position_open_and_close() {
        let tracker = PositionTracker::new();
        let sym = Symbol::from("AAPL");

        // Step 1: Buy 10 shares at $100
        let buy_order = make_test_order("AAPL", OrderSide::Buy, 10.0);
        let buy_price = Price::from_f64(100.0).unwrap();
        tracker
            .update_position(&sym, &buy_order, buy_price)
            .await
            .unwrap();

        // Verify the position exists with correct quantity
        let positions = tracker.get_all_positions().await;
        assert_eq!(positions.len(), 1);
        let pos = positions.get(&sym).unwrap();
        assert!(pos.quantity > Decimal::ZERO, "Position should be long");

        // Step 2: Sell 10 shares at $110 -- closes the position
        let sell_order = make_test_order("AAPL", OrderSide::Sell, 10.0);
        let sell_price = Price::from_f64(110.0).unwrap();
        tracker
            .update_position(&sym, &sell_order, sell_price)
            .await
            .unwrap();

        // Position should be removed after full close
        let positions = tracker.get_all_positions().await;
        assert!(
            positions.is_empty(),
            "Position should be removed after full close"
        );

        // A round-trip trade record should have been created with correct PnL
        let trades = tracker.get_trades().await;
        assert_eq!(trades.len(), 1, "One round-trip trade expected");
        let trade = &trades[0];
        // PnL = (110 - 100) * 10 = 100
        assert_eq!(trade.pnl, Decimal::from(100));
        assert_eq!(trade.side, OrderSide::Buy); // entry side was Buy
    }

    #[tokio::test]
    async fn test_position_tracker_short_position_pnl() {
        let tracker = PositionTracker::new();
        let sym = Symbol::from("TSLA");

        // Sell short 5 shares at $200
        let sell_order = make_test_order("TSLA", OrderSide::Sell, 5.0);
        let sell_price = Price::from_f64(200.0).unwrap();
        tracker
            .update_position(&sym, &sell_order, sell_price)
            .await
            .unwrap();

        let positions = tracker.get_all_positions().await;
        let pos = positions.get(&sym).unwrap();
        assert!(pos.quantity < Decimal::ZERO, "Position should be short");

        // Cover (buy) 5 shares at $180 -- profit on short
        let buy_order = make_test_order("TSLA", OrderSide::Buy, 5.0);
        let buy_price = Price::from_f64(180.0).unwrap();
        tracker
            .update_position(&sym, &buy_order, buy_price)
            .await
            .unwrap();

        let positions = tracker.get_all_positions().await;
        assert!(positions.is_empty(), "Short position should be closed");

        let trades = tracker.get_trades().await;
        assert_eq!(trades.len(), 1);
        // Short PnL = (entry 200 - exit 180) * 5 = 100
        assert_eq!(trades[0].pnl, Decimal::from(100));
    }

    #[tokio::test]
    async fn test_position_tracker_get_realized_pnl() {
        let tracker = PositionTracker::new();

        // Trade 1: Buy 10 AAPL at $100, sell at $110 => PnL = +100
        let sym1 = Symbol::from("AAPL");
        let buy1 = make_test_order("AAPL", OrderSide::Buy, 10.0);
        let sell1 = make_test_order("AAPL", OrderSide::Sell, 10.0);
        tracker
            .update_position(&sym1, &buy1, Price::from_f64(100.0).unwrap())
            .await
            .unwrap();
        tracker
            .update_position(&sym1, &sell1, Price::from_f64(110.0).unwrap())
            .await
            .unwrap();

        // Trade 2: Buy 5 MSFT at $300, sell at $290 => PnL = -50
        let sym2 = Symbol::from("MSFT");
        let buy2 = make_test_order("MSFT", OrderSide::Buy, 5.0);
        let sell2 = make_test_order("MSFT", OrderSide::Sell, 5.0);
        tracker
            .update_position(&sym2, &buy2, Price::from_f64(300.0).unwrap())
            .await
            .unwrap();
        tracker
            .update_position(&sym2, &sell2, Price::from_f64(290.0).unwrap())
            .await
            .unwrap();

        // Total realized PnL should be 100 + (-50) = 50
        let total_pnl = tracker.get_realized_pnl().await;
        assert_eq!(total_pnl, Decimal::from(50));

        let trades = tracker.get_trades().await;
        assert_eq!(trades.len(), 2, "Two round-trip trades expected");
    }

    #[tokio::test]
    async fn test_position_tracker_partial_close() {
        let tracker = PositionTracker::new();
        let sym = Symbol::from("GOOG");

        // Buy 20 at $50
        let buy = make_test_order("GOOG", OrderSide::Buy, 20.0);
        tracker
            .update_position(&sym, &buy, Price::from_f64(50.0).unwrap())
            .await
            .unwrap();

        // Sell 10 at $60 -- partial close
        let sell = make_test_order("GOOG", OrderSide::Sell, 10.0);
        tracker
            .update_position(&sym, &sell, Price::from_f64(60.0).unwrap())
            .await
            .unwrap();

        // 10 shares should remain
        let positions = tracker.get_all_positions().await;
        assert_eq!(positions.len(), 1);
        let pos = positions.get(&sym).unwrap();
        assert_eq!(pos.quantity, Decimal::from(10));

        // Realized PnL from the closed 10 shares: (60-50)*10 = 100
        let pnl = tracker.get_realized_pnl().await;
        assert_eq!(pnl, Decimal::from(100));
    }

    #[tokio::test]
    async fn test_position_tracker_add_to_position() {
        let tracker = PositionTracker::new();
        let sym = Symbol::from("AMZN");

        // Buy 10 at $100
        let buy1 = make_test_order("AMZN", OrderSide::Buy, 10.0);
        tracker
            .update_position(&sym, &buy1, Price::from_f64(100.0).unwrap())
            .await
            .unwrap();

        // Buy 10 more at $120 -- adding to position
        let buy2 = make_test_order("AMZN", OrderSide::Buy, 10.0);
        tracker
            .update_position(&sym, &buy2, Price::from_f64(120.0).unwrap())
            .await
            .unwrap();

        let positions = tracker.get_all_positions().await;
        let pos = positions.get(&sym).unwrap();
        assert_eq!(pos.quantity, Decimal::from(20));
        // Weighted avg: (100*10 + 120*10) / 20 = 110
        assert_eq!(pos.avg_price, Decimal::from(110));

        // No realized PnL yet (no close)
        let pnl = tracker.get_realized_pnl().await;
        assert_eq!(pnl, Decimal::ZERO);
    }
}
