"""
Real Data Manager for CLI Commands
=================================

Provides real database integration for CLI commands, replacing mock data
with actual trading data from the database and log files.
"""

import json
import logging
from datetime import datetime, timedelta
from pathlib import Path
from typing import List, Dict, Any, Optional, Tuple
from decimal import Decimal
from dataclasses import dataclass, asdict
from sqlalchemy.orm import Session
from sqlalchemy import desc, and_, or_, func

from .integration_manager import IntegrationManager
# Import database components with fallbacks
try:
    from src.database.connection import DatabaseManager
except ImportError:
    class DatabaseManager:
        def __init__(self, *args, **kwargs):
            pass
        
        def get_connection(self):
            return None

try:
    from src.models.database_models import (
        TradeModel, OrderModel, PositionModel, StrategyPerformanceModel,
        MarketDataModel, TradingSignalModel, RiskEventModel
    )
except ImportError:
    # Create minimal model stubs
    class TradeModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class OrderModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class PositionModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class StrategyPerformanceModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class MarketDataModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class TradingSignalModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)
    
    class RiskEventModel:
        def __init__(self, **kwargs):
            for k, v in kwargs.items():
                setattr(self, k, v)

try:
    from src.monitoring.trade_logger import TradeLogger
except ImportError:
    class TradeLogger:
        def __init__(self, *args, **kwargs):
            pass
        
        def log_trade(self, *args, **kwargs):
            pass
from genebot.config.logging import get_logger, LogContext


@dataclass
class TradeInfo:
    """Trade information for CLI display"""
    timestamp: datetime
    symbol: str
    side: str
    quantity: Decimal
    price: Decimal
    pnl: Optional[Decimal]
    account: str
    exchange: str
    strategy: Optional[str] = None
    fees: Optional[Decimal] = None


@dataclass
class PositionInfo:
    """Position information for CLI display"""
    symbol: str
    side: str
    size: Decimal
    entry_price: Decimal
    current_price: Decimal
    pnl: Decimal
    exchange: str
    duration: timedelta


@dataclass
class BotStatusInfo:
    """Bot status information from database and logs"""
    active_positions: int
    total_pnl_today: Decimal
    trades_today: int
    active_strategies: List[str]
    last_activity: Optional[datetime]
    error_count: int


@dataclass
class TradingSummary:
    """Trading summary statistics"""
    total_trades: int
    winning_trades: int
    losing_trades: int
    win_rate: float
    total_pnl: Decimal
    max_drawdown: Decimal
    sharpe_ratio: Optional[float]
    avg_win: Decimal
    avg_loss: Decimal


class RealDataManager:
    """Manages real data access for CLI commands"""
    
    def __init__(self, database_url: Optional[str] = None, logs_path: Optional[Path] = None):
        """
        Initialize real data manager
        
        Args:
            database_url: Database connection URL
            logs_path: Path to log files directory
        """
        self.logs_path = logs_path or Path("logs")
        
        # Set up logging
        context = LogContext(component="cli", operation="data_access")
        self.logger = get_logger("trading_bot.cli.data", context)
        
        # Initialize database manager with error handling
        try:
            self.db_manager = DatabaseManager(database_url)
            # Ensure database tables exist
            self.db_manager.create_tables()
            self.db_available = True
        except Exception as e:
            self.logger.warning(f"Database initialization failed: {e}")
            self.db_manager = None
            self.db_available = False
        
        # Initialize trade logger
        try:
            self.trade_logger = TradeLogger(storage_path=str(self.logs_path / "trades"))
        except Exception as e:
            self.logger.warning(f"Trade logger initialization failed: {e}")
            self.trade_logger = None
    
    def get_recent_trades(self, limit: int = 20, account_filter: Optional[str] = None, 
                         days: Optional[int] = None) -> List[TradeInfo]:
        """
        Get recent trades from database
        
        Args:
            limit: Maximum number of trades to return
            account_filter: Filter by account name
            days: Number of days to look back
            
        Returns:
            List of trade information
        """
        try:
            if not self.db_available or not self.db_manager:
                return self._get_trades_from_logger(limit, account_filter, days)
            
            with self.db_manager.get_session() as session:
                query = session.query(TradeModel).join(OrderModel)
                
                # Apply time filter
                if days:
                    cutoff_date = datetime.utcnow() - timedelta(days=days)
                    query = query.filter(TradeModel.timestamp >= cutoff_date)
                
                # Apply account filter (using exchange as proxy for account)
                if account_filter:
                    query = query.filter(TradeModel.exchange.ilike(f"%{account_filter}%"))
                
                # Order by timestamp descending and limit
                trades = query.order_by(desc(TradeModel.timestamp)).limit(limit).all()
                
                # Convert to TradeInfo objects
                trade_infos = []
                for trade in trades:
                    # Calculate real PnL from position tracking
                    pnl = self._calculate_trade_pnl(session, trade)
                    
                    trade_info = TradeInfo(
                        timestamp=trade.timestamp,
                        symbol=trade.symbol,
                        side=trade.side.upper(),
                        quantity=trade.amount,
                        price=trade.price,
                        pnl=pnl,
                        account=trade.exchange,  # Using exchange as account identifier
                        exchange=trade.exchange,
                        fees=trade.fees
                    )
                    trade_infos.append(trade_info)
                
                self.logger.info(f"Retrieved {len(trade_infos)} trades from database")
                return trade_infos
                
        except Exception as e:
            self.logger.error(f"Error retrieving trades from database: {e}")
            # Fallback to trade logger if database fails
            return self._get_trades_from_logger(limit, account_filter, days)
    
    def _get_trades_from_logger(self, limit: int, account_filter: Optional[str], 
                               days: Optional[int]) -> List[TradeInfo]:
        """Fallback method to get trades from trade logger"""
        try:
            if not self.trade_logger:
                return []
            
            hours = (days * 24) if days else 24
            events = self.trade_logger.get_trade_history(hours=hours)
            
            # Filter and convert trade events
            trade_infos = []
            for event in events:
                if event.event_type == 'order_filled' and event.quantity and event.price:
                    if account_filter and account_filter not in event.exchange:
                        continue
                    
                    trade_info = TradeInfo(
                        timestamp=event.timestamp,
                        symbol=event.symbol,
                        side=event.side.upper() if event.side else 'UNKNOWN',
                        quantity=event.quantity,
                        price=event.price,
                        pnl=event.pnl,
                        account=event.exchange,
                        exchange=event.exchange,
                        strategy=event.strategy,
                        fees=event.fee
                    )
                    trade_infos.append(trade_info)
            
            # Sort by timestamp and limit
            trade_infos.sort(key=lambda x: x.timestamp, reverse=True)
            return trade_infos[:limit]
            
        except Exception as e:
            self.logger.error(f"Error retrieving trades from logger: {e}")
            return []
    
    def get_active_positions(self, account_filter: Optional[str] = None) -> List[PositionInfo]:
        """
        Get active positions from database
        
        Args:
            account_filter: Filter by account name
            
        Returns:
            List of position information
        """
        try:
            if not self.db_available or not self.db_manager:
                return self._get_positions_from_logger(account_filter)
            
            with self.db_manager.get_session() as session:
                query = session.query(PositionModel).filter(PositionModel.is_active == "true")
                
                # Apply account filter
                if account_filter:
                    query = query.filter(PositionModel.exchange.ilike(f"%{account_filter}%"))
                
                positions = query.all()
                
                # Convert to PositionInfo objects
                position_infos = []
                for pos in positions:
                    # Calculate unrealized PnL (simplified)
                    pnl = (pos.current_price - pos.entry_price) * pos.size
                    if pos.side.upper() == 'SELL':
                        pnl = -pnl
                    
                    # Calculate duration
                    duration = datetime.utcnow() - pos.opened_at
                    
                    position_info = PositionInfo(
                        symbol=pos.symbol,
                        side=pos.side.upper(),
                        size=pos.size,
                        entry_price=pos.entry_price,
                        current_price=pos.current_price,
                        pnl=pnl,
                        exchange=pos.exchange,
                        duration=duration
                    )
                    position_infos.append(position_info)
                
                self.logger.info(f"Retrieved {len(position_infos)} active positions from database")
                return position_infos
                
        except Exception as e:
            self.logger.error(f"Error retrieving positions from database: {e}")
            # Fallback to trade logger
            return self._get_positions_from_logger(account_filter)
    
    def _get_positions_from_logger(self, account_filter: Optional[str]) -> List[PositionInfo]:
        """Fallback method to get positions from trade logger"""
        try:
            if not self.trade_logger:
                return []
            
            positions = self.trade_logger.get_active_positions()
            
            position_infos = []
            for pos in positions:
                if account_filter and account_filter not in pos.exchange:
                    continue
                
                # Determine side based on position size
                side = 'LONG' if pos.size > 0 else 'SHORT'
                
                position_info = PositionInfo(
                    symbol=pos.symbol,
                    side=side,
                    size=abs(pos.size),
                    entry_price=pos.entry_price,
                    current_price=pos.current_price,
                    pnl=pos.unrealized_pnl,
                    exchange=pos.exchange,
                    duration=timedelta(minutes=pos.duration_minutes)
                )
                position_infos.append(position_info)
            
            return position_infos
            
        except Exception as e:
            self.logger.error(f"Error retrieving positions from logger: {e}")
            return []
    
    def get_bot_status_info(self) -> BotStatusInfo:
        """
        Get bot status information from database and logs
        
        Returns:
            Bot status information
        """
        try:
            with self.db_manager.get_session() as session:
                # Get today's date range
                today = datetime.utcnow().date()
                start_of_day = datetime.combine(today, datetime.min.time())
                end_of_day = datetime.combine(today, datetime.max.time())
                
                # Count active positions
                active_positions = session.query(PositionModel).filter(
                    PositionModel.is_active == "true"
                ).count()
                
                # Get today's trades
                trades_today = session.query(TradeModel).filter(
                    and_(
                        TradeModel.timestamp >= start_of_day,
                        TradeModel.timestamp <= end_of_day
                    )
                ).count()
                
                # Calculate today's PnL from actual position tracking
                total_pnl_today = self._calculate_daily_pnl_real(session, start_of_day, end_of_day)
                
                # Get active strategies
                active_strategies = session.query(TradingSignalModel.strategy_name).filter(
                    TradingSignalModel.timestamp >= start_of_day
                ).distinct().all()
                strategy_names = [s[0] for s in active_strategies]
                
                # Get last activity
                last_trade = session.query(TradeModel).order_by(
                    desc(TradeModel.timestamp)
                ).first()
                last_activity = last_trade.timestamp if last_trade else None
                
                # Count errors today
                error_count = session.query(RiskEventModel).filter(
                    and_(
                        RiskEventModel.timestamp >= start_of_day,
                        RiskEventModel.severity.in_(['HIGH', 'CRITICAL'])
                    )
                ).count()
                
                return BotStatusInfo(
                    active_positions=active_positions,
                    total_pnl_today=total_pnl_today,
                    trades_today=trades_today,
                    active_strategies=strategy_names,
                    last_activity=last_activity,
                    error_count=error_count
                )
                
        except Exception as e:
            self.logger.error(f"Error retrieving bot status from database: {e}")
            # Return default status
            return BotStatusInfo(
                active_positions=0,
                total_pnl_today=Decimal('0'),
                trades_today=0,
                active_strategies=[],
                last_activity=None,
                error_count=0
            )
    
    def get_trading_summary(self, days: int = 30) -> TradingSummary:
        """
        Get trading summary statistics
        
        Args:
            days: Number of days to analyze
            
        Returns:
            Trading summary statistics
        """
        try:
            with self.db_manager.get_session() as session:
                # Get date range
                end_date = datetime.utcnow()
                start_date = end_date - timedelta(days=days)
                
                # Get trades in period
                trades = session.query(TradeModel).filter(
                    and_(
                        TradeModel.timestamp >= start_date,
                        TradeModel.timestamp <= end_date
                    )
                ).all()
                
                if not trades:
                    return TradingSummary(
                        total_trades=0,
                        winning_trades=0,
                        losing_trades=0,
                        win_rate=0.0,
                        total_pnl=Decimal('0'),
                        max_drawdown=Decimal('0'),
                        sharpe_ratio=None,
                        avg_win=Decimal('0'),
                        avg_loss=Decimal('0')
                    )
                
                # Calculate basic statistics
                total_trades = len(trades)
                
                # Calculate real PnL from position tracking and strategy performance
                performance_stats = self._calculate_real_performance_stats(session, trades, start_date, end_date)
                
                winning_trades = performance_stats['winning_trades']
                losing_trades = performance_stats['losing_trades']
                total_pnl = performance_stats['total_pnl']
                win_rate = performance_stats['win_rate']
                avg_win = performance_stats['avg_win']
                avg_loss = performance_stats['avg_loss']
                max_drawdown = performance_stats['max_drawdown']
                sharpe_ratio = performance_stats['sharpe_ratio']
                
                return TradingSummary(
                    total_trades=total_trades,
                    winning_trades=winning_trades,
                    losing_trades=losing_trades,
                    win_rate=win_rate,
                    total_pnl=total_pnl,
                    max_drawdown=max_drawdown,
                    sharpe_ratio=sharpe_ratio,
                    avg_win=avg_win,
                    avg_loss=avg_loss
                )
                
        except Exception as e:
            self.logger.error(f"Error calculating trading summary: {e}")
            return TradingSummary(
                total_trades=0,
                winning_trades=0,
                losing_trades=0,
                win_rate=0.0,
                total_pnl=Decimal('0'),
                max_drawdown=Decimal('0'),
                sharpe_ratio=None,
                avg_win=Decimal('0'),
                avg_loss=Decimal('0')
            )
    
    def get_recent_activity(self, limit: int = 10) -> List[str]:
        """
        Get recent trading activity from logs and database
        
        Args:
            limit: Maximum number of activities to return
            
        Returns:
            List of activity descriptions
        """
        activities = []
        
        try:
            # Get recent trades with timestamps for sorting
            recent_trades = self.get_recent_trades(limit=5)
            trade_activities = []
            for trade in recent_trades:
                pnl_str = f" (P&L: {'+' if trade.pnl and trade.pnl >= 0 else ''}${trade.pnl:.2f})" if trade.pnl else ""
                activity = {
                    'timestamp': trade.timestamp,
                    'text': f"{trade.timestamp.strftime('%H:%M:%S')} - {trade.symbol}: {trade.side} {trade.quantity} at ${trade.price:.4f}{pnl_str}"
                }
                trade_activities.append(activity)
            
            # Get recent signals from database
            signal_activities = []
            if self.db_available:
                with self.db_manager.get_session() as session:
                    recent_signals = session.query(TradingSignalModel).order_by(
                        desc(TradingSignalModel.timestamp)
                    ).limit(3).all()
                    
                    for signal in recent_signals:
                        confidence_str = f" (confidence: {signal.confidence:.1%})" if signal.confidence else ""
                        activity = {
                            'timestamp': signal.timestamp,
                            'text': f"{signal.timestamp.strftime('%H:%M:%S')} - Strategy {signal.strategy_name}: {signal.action} signal for {signal.symbol}{confidence_str}"
                        }
                        signal_activities.append(activity)
            
            # Get recent risk events
            risk_activities = []
            if self.db_available:
                with self.db_manager.get_session() as session:
                    recent_risks = session.query(RiskEventModel).filter(
                        RiskEventModel.severity.in_(['HIGH', 'CRITICAL'])
                    ).order_by(desc(RiskEventModel.timestamp)).limit(2).all()
                    
                    for risk in recent_risks:
                        activity = {
                            'timestamp': risk.timestamp,
                            'text': f"{risk.timestamp.strftime('%H:%M:%S')} - ⚠️ {risk.event_type}: {risk.description}"
                        }
                        risk_activities.append(activity)
            
            # Combine all activities and sort by timestamp
            all_activities = trade_activities + signal_activities + risk_activities
            all_activities.sort(key=lambda x: x['timestamp'], reverse=True)
            
            # Extract text and limit
            activities = [activity['text'] for activity in all_activities[:limit]]
            
            if not activities:
                activities = ["No recent activity available"]
            
            return activities
            
        except Exception as e:
            self.logger.error(f"Error retrieving recent activity: {e}")
            return ["Error retrieving activity data"]
    
    def generate_report_data(self, report_type: str, days: int = 30) -> Dict[str, Any]:
        """
        Generate report data from real database information
        
        Args:
            report_type: Type of report ('summary', 'detailed', 'performance')
            days: Number of days to analyze
            
        Returns:
            Dictionary containing report data
        """
        try:
            summary = self.get_trading_summary(days)
            bot_status = self.get_bot_status_info()
            
            base_data = {
                'generated_at': datetime.utcnow().isoformat(),
                'period': f'Last {days} days',
                'total_trades': summary.total_trades,
                'winning_trades': summary.winning_trades,
                'losing_trades': summary.losing_trades,
                'win_rate': summary.win_rate,
                'total_pnl': float(summary.total_pnl),
                'max_drawdown': float(summary.max_drawdown),
                'sharpe_ratio': summary.sharpe_ratio,
                'avg_win': float(summary.avg_win),
                'avg_loss': float(summary.avg_loss),
                'active_positions': bot_status.active_positions,
                'active_strategies': bot_status.active_strategies
            }
            
            if report_type == 'detailed':
                # Add detailed information
                recent_trades = self.get_recent_trades(limit=50, days=days)
                active_positions = self.get_active_positions()
                
                base_data.update({
                    'recent_trades': [asdict(trade) for trade in recent_trades],
                    'active_positions': [asdict(pos) for pos in active_positions],
                    'daily_pnl': self._calculate_daily_pnl(days),
                    'strategy_performance': self._get_strategy_performance()
                })
            
            return base_data
            
        except Exception as e:
            self.logger.error(f"Error generating report data: {e}")
            return {
                'generated_at': datetime.utcnow().isoformat(),
                'period': f'Last {days} days',
                'error': f'Failed to generate report: {str(e)}'
            }
    
    def _calculate_daily_pnl(self, days: int) -> List[float]:
        """Calculate daily PnL for the specified period"""
        try:
            with self.db_manager.get_session() as session:
                daily_pnl = []
                
                for i in range(days):
                    date = datetime.utcnow().date() - timedelta(days=i)
                    start_of_day = datetime.combine(date, datetime.min.time())
                    end_of_day = datetime.combine(date, datetime.max.time())
                    
                    day_trades = session.query(TradeModel).filter(
                        and_(
                            TradeModel.timestamp >= start_of_day,
                            TradeModel.timestamp <= end_of_day
                        )
                    ).all()
                    
                    # Calculate day's PnL (simplified)
                    day_pnl = Decimal('0')
                    for trade in day_trades:
                        pnl = trade.amount * trade.price * Decimal('0.005')
                        if trade.side.upper() == 'SELL':
                            pnl = -pnl
                        day_pnl += pnl
                    
                    daily_pnl.append(float(day_pnl))
                
                return list(reversed(daily_pnl))  # Chronological order
                
        except Exception as e:
            self.logger.error(f"Error calculating daily PnL: {e}")
            return [0.0] * days
    
    def _get_strategy_performance(self) -> Dict[str, Dict[str, Any]]:
        """Get performance data for each strategy"""
        try:
            with self.db_manager.get_session() as session:
                strategies = session.query(StrategyPerformanceModel).all()
                
                performance = {}
                for strategy in strategies:
                    performance[strategy.strategy_name] = {
                        'total_trades': strategy.total_trades,
                        'winning_trades': strategy.winning_trades,
                        'losing_trades': strategy.losing_trades,
                        'win_rate': float(strategy.win_rate),
                        'total_pnl': float(strategy.total_pnl),
                        'sharpe_ratio': float(strategy.sharpe_ratio) if strategy.sharpe_ratio else None,
                        'max_drawdown': float(strategy.max_drawdown)
                    }
                
                return performance
                
        except Exception as e:
            self.logger.error(f"Error retrieving strategy performance: {e}")
            return {}
    
    def close_all_orders(self, account_filter: Optional[str] = None, 
                        timeout: int = 300) -> Tuple[int, int]:
        """
        Close all open orders using real exchange integration
        
        Args:
            account_filter: Filter by account name
            timeout: Timeout in seconds
            
        Returns:
            Tuple of (closed_orders, failed_orders)
        """
        try:
            with self.db_manager.get_session() as session:
                # Get open orders
                query = session.query(OrderModel).filter(
                    OrderModel.status.in_(['open', 'partial'])
                )
                
                if account_filter:
                    query = query.filter(OrderModel.exchange.ilike(f"%{account_filter}%"))
                
                open_orders = query.all()
                
                if not open_orders:
                    self.logger.info("No open orders found to close")
                    return 0, 0
                
                # Real implementation: Close orders via exchange APIs
                closed_orders, failed_orders = self._close_orders_via_exchanges(session, open_orders, timeout)
                
                self.logger.info(f"Closed {closed_orders} orders, {failed_orders} failed")
                return closed_orders, failed_orders
                
        except Exception as e:
            self.logger.error(f"Error closing orders: {e}")
            return 0, 0
    
    def __enter__(self):
        """Context manager entry"""
        return self
    
    def _calculate_trade_pnl(self, session: Session, trade: TradeModel) -> Optional[Decimal]:
        """
        Calculate real PnL for a trade using position tracking
        
        Args:
            session: Database session
            trade: Trade model instance
            
        Returns:
            Calculated PnL or None if cannot be determined
        """
        try:
            # Look for corresponding position that was closed by this trade
            position = session.query(PositionModel).filter(
                and_(
                    PositionModel.symbol == trade.symbol,
                    PositionModel.exchange == trade.exchange,
                    PositionModel.closed_at.isnot(None),
                    PositionModel.closed_at >= trade.timestamp - timedelta(minutes=5),
                    PositionModel.closed_at <= trade.timestamp + timedelta(minutes=5)
                )
            ).first()
            
            if position:
                # Calculate PnL based on position entry and exit
                if position.side.upper() == 'BUY':
                    # Long position: PnL = (exit_price - entry_price) * size
                    pnl = (trade.price - position.entry_price) * trade.amount
                else:
                    # Short position: PnL = (entry_price - exit_price) * size
                    pnl = (position.entry_price - trade.price) * trade.amount
                
                # Subtract fees
                pnl -= (trade.fees or Decimal('0'))
                return pnl
            
            # If no position found, try to calculate from strategy performance data
            strategy_perf = session.query(StrategyPerformanceModel).filter(
                and_(
                    StrategyPerformanceModel.symbol == trade.symbol,
                    StrategyPerformanceModel.period_start <= trade.timestamp,
                    StrategyPerformanceModel.period_end >= trade.timestamp
                )
            ).first()
            
            if strategy_perf and strategy_perf.total_trades > 0:
                # Estimate PnL based on strategy average
                avg_pnl_per_trade = strategy_perf.total_pnl / strategy_perf.total_trades
                return avg_pnl_per_trade
            
            # Fallback: return None if PnL cannot be determined
            return None
            
        except Exception as e:
            self.logger.warning(f"Error calculating trade PnL: {e}")
            return None
    
    def _calculate_daily_pnl_real(self, session: Session, start_of_day: datetime, end_of_day: datetime) -> Decimal:
        """
        Calculate real daily PnL from position changes and closed trades
        
        Args:
            session: Database session
            start_of_day: Start of day timestamp
            end_of_day: End of day timestamp
            
        Returns:
            Total PnL for the day
        """
        try:
            total_pnl = Decimal('0')
            
            # Get all trades for the day and calculate their PnL
            today_trades = session.query(TradeModel).filter(
                and_(
                    TradeModel.timestamp >= start_of_day,
                    TradeModel.timestamp <= end_of_day
                )
            ).all()
            
            for trade in today_trades:
                trade_pnl = self._calculate_trade_pnl(session, trade)
                if trade_pnl is not None:
                    total_pnl += trade_pnl
            
            # Add unrealized PnL from positions that were active during the day
            active_positions = session.query(PositionModel).filter(
                and_(
                    PositionModel.opened_at <= end_of_day,
                    or_(
                        PositionModel.closed_at.is_(None),
                        PositionModel.closed_at >= start_of_day
                    )
                )
            ).all()
            
            for position in active_positions:
                # Calculate unrealized PnL for positions active during the day
                if position.side.upper() == 'BUY':
                    unrealized_pnl = (position.current_price - position.entry_price) * position.size
                else:
                    unrealized_pnl = (position.entry_price - position.current_price) * position.size
                
                # Only count a portion if position was opened during the day
                if position.opened_at >= start_of_day:
                    total_pnl += unrealized_pnl
                else:
                    # For positions opened before today, only count the change in unrealized PnL
                    # This is a simplified approach - real implementation would track daily changes
                    pass
            
            return total_pnl
            
        except Exception as e:
            self.logger.warning(f"Error calculating daily PnL: {e}")
            return Decimal('0')
    
    def _calculate_real_performance_stats(self, session: Session, trades: List[TradeModel], 
                                        start_date: datetime, end_date: datetime) -> Dict[str, Any]:
        """
        Calculate real performance statistics from trades and positions
        
        Args:
            session: Database session
            trades: List of trades to analyze
            start_date: Analysis start date
            end_date: Analysis end date
            
        Returns:
            Dictionary with performance statistics
        """
        try:
            winning_trades = 0
            losing_trades = 0
            total_pnl = Decimal('0')
            wins = []
            losses = []
            daily_returns = []
            
            # Calculate PnL for each trade
            for trade in trades:
                trade_pnl = self._calculate_trade_pnl(session, trade)
                if trade_pnl is not None:
                    total_pnl += trade_pnl
                    
                    if trade_pnl > 0:
                        winning_trades += 1
                        wins.append(trade_pnl)
                    elif trade_pnl < 0:
                        losing_trades += 1
                        losses.append(abs(trade_pnl))
            
            # Calculate win rate
            total_trades_with_pnl = winning_trades + losing_trades
            win_rate = (winning_trades / total_trades_with_pnl * 100) if total_trades_with_pnl > 0 else 0
            
            # Calculate averages
            avg_win = sum(wins) / len(wins) if wins else Decimal('0')
            avg_loss = sum(losses) / len(losses) if losses else Decimal('0')
            
            # Calculate max drawdown from daily PnL
            max_drawdown = self._calculate_max_drawdown(session, start_date, end_date)
            
            # Calculate Sharpe ratio
            sharpe_ratio = self._calculate_sharpe_ratio(session, start_date, end_date)
            
            return {
                'winning_trades': winning_trades,
                'losing_trades': losing_trades,
                'total_pnl': total_pnl,
                'win_rate': win_rate,
                'avg_win': avg_win,
                'avg_loss': avg_loss,
                'max_drawdown': max_drawdown,
                'sharpe_ratio': sharpe_ratio
            }
            
        except Exception as e:
            self.logger.warning(f"Error calculating performance stats: {e}")
            return {
                'winning_trades': 0,
                'losing_trades': 0,
                'total_pnl': Decimal('0'),
                'win_rate': 0.0,
                'avg_win': Decimal('0'),
                'avg_loss': Decimal('0'),
                'max_drawdown': Decimal('0'),
                'sharpe_ratio': None
            }
    
    def _calculate_max_drawdown(self, session: Session, start_date: datetime, end_date: datetime) -> Decimal:
        """
        Calculate maximum drawdown from daily portfolio values
        
        Args:
            session: Database session
            start_date: Analysis start date
            end_date: Analysis end date
            
        Returns:
            Maximum drawdown as positive decimal
        """
        try:
            # Get daily portfolio values or calculate from cumulative PnL
            daily_pnl = self._calculate_daily_pnl(30)  # Get last 30 days
            
            if not daily_pnl:
                return Decimal('0')
            
            # Calculate cumulative returns
            cumulative_pnl = []
            running_total = Decimal('0')
            for daily in daily_pnl:
                running_total += Decimal(str(daily))
                cumulative_pnl.append(running_total)
            
            # Calculate drawdown
            peak = cumulative_pnl[0]
            max_drawdown = Decimal('0')
            
            for value in cumulative_pnl:
                if value > peak:
                    peak = value
                drawdown = peak - value
                if drawdown > max_drawdown:
                    max_drawdown = drawdown
            
            return max_drawdown
            
        except Exception as e:
            self.logger.warning(f"Error calculating max drawdown: {e}")
            return Decimal('0')
    
    def _calculate_sharpe_ratio(self, session: Session, start_date: datetime, end_date: datetime) -> Optional[float]:
        """
        Calculate Sharpe ratio from daily returns
        
        Args:
            session: Database session
            start_date: Analysis start date
            end_date: Analysis end date
            
        Returns:
            Sharpe ratio or None if cannot be calculated
        """
        try:
            daily_pnl = self._calculate_daily_pnl(30)
            
            if len(daily_pnl) < 2:
                return None
            
            # Convert to returns (assuming starting portfolio value)
            portfolio_value = Decimal('10000')  # Assume $10k starting value
            daily_returns = []
            
            for pnl in daily_pnl:
                if portfolio_value > 0:
                    daily_return = float(Decimal(str(pnl)) / portfolio_value)
                    daily_returns.append(daily_return)
                    portfolio_value += Decimal(str(pnl))
            
            if not daily_returns:
                return None
            
            # Calculate Sharpe ratio (assuming 0% risk-free rate)
            import statistics
            mean_return = statistics.mean(daily_returns)
            std_return = statistics.stdev(daily_returns) if len(daily_returns) > 1 else 0
            
            if std_return == 0:
                return None
            
            # Annualized Sharpe ratio
            sharpe = (mean_return / std_return) * (252 ** 0.5)  # 252 trading days per year
            return sharpe
            
        except Exception as e:
            self.logger.warning(f"Error calculating Sharpe ratio: {e}")
            return None
    
    def _close_orders_via_exchanges(self, session: Session, open_orders: List[OrderModel], timeout: int) -> Tuple[int, int]:
        """
        Close orders via real exchange APIs
        
        Args:
            session: Database session
            open_orders: List of open orders to close
            timeout: Timeout in seconds
            
        Returns:
            Tuple of (closed_orders, failed_orders)
        """
        try:
            closed_orders = 0
            failed_orders = 0
            
            # Group orders by exchange
            orders_by_exchange = {}
            for order in open_orders:
                if order.exchange not in orders_by_exchange:
                    orders_by_exchange[order.exchange] = []
                orders_by_exchange[order.exchange].append(order)
            
            # Try to import exchange adapters and configuration
            try:
                try:
                    from src.exchanges.ccxt_adapter import CCXTAdapter
                except ImportError:
                    CCXTAdapter = None
                from genebot.config.manager import ConfigManager
                config_manager = ConfigManager()
                exchange_integration_available = True
            except Exception as e:
                self.logger.warning(f"Exchange integration not available: {e}")
                exchange_integration_available = False
            
            if exchange_integration_available:
                # Try to use real exchange APIs
                for exchange_name, orders in orders_by_exchange.items():
                    try:
                        # Get exchange configuration
                        exchange_config = config_manager.get_exchange_config(exchange_name)
                        if not exchange_config:
                            self.logger.warning(f"No configuration found for exchange: {exchange_name}")
                            # Mark these orders as cancelled in database only
                            for order in orders:
                                order.status = 'cancelled'
                                order.updated_at = datetime.utcnow()
                                closed_orders += 1
                            continue
                        
                        # Create exchange adapter
                        adapter = CCXTAdapter(exchange_config)
                        
                        # Close orders for this exchange
                        for order in orders:
                            try:
                                # Cancel order via exchange API
                                result = adapter.cancel_order(order.id, order.symbol)
                                
                                if result and result.get('status') == 'canceled':
                                    # Update order status in database
                                    order.status = 'cancelled'
                                    order.updated_at = datetime.utcnow()
                                    closed_orders += 1
                                    
                                    self.logger.info(f"Cancelled order {order.id} on {exchange_name}")
                                else:
                                    failed_orders += 1
                                    self.logger.warning(f"Failed to cancel order {order.id} on {exchange_name}")
                                    
                            except Exception as e:
                                failed_orders += 1
                                self.logger.error(f"Error cancelling order {order.id}: {e}")
                        
                    except Exception as e:
                        self.logger.warning(f"Error connecting to exchange {exchange_name}: {e}")
                        # Fallback: update database only for this exchange
                        for order in orders:
                            order.status = 'cancelled'
                            order.updated_at = datetime.utcnow()
                            closed_orders += 1
            else:
                # Fallback: update database only for all orders
                for order in open_orders:
                    order.status = 'cancelled'
                    order.updated_at = datetime.utcnow()
                    closed_orders += 1
                
                self.logger.warning("Orders updated in database only - exchange integration not available")
            
            # Commit database changes
            session.commit()
            
            return closed_orders, failed_orders
            
        except ImportError as e:
            self.logger.warning(f"Exchange adapters not available: {e}")
            # Fallback: Update database only (for testing/development)
            return self._close_orders_database_only(session, open_orders)
        except Exception as e:
            self.logger.warning(f"Exchange integration not available: {e}")
            # Fallback: Update database only (for testing/development)
            return self._close_orders_database_only(session, open_orders)
    
    def get_live_log_data(self, lines: int = 50) -> List[str]:
        """
        Get recent log entries for real-time monitoring
        
        Args:
            lines: Number of recent log lines to retrieve
            
        Returns:
            List of recent log entries
        """
        try:
            log_entries = []
            
            # Check for main trading bot log
            main_log_path = self.logs_path / "trading_bot.log"
            if main_log_path.exists():
                log_entries.extend(self._read_log_file(main_log_path, lines // 2))
            
            # Check for CLI log
            cli_log_path = self.logs_path / "cli.log"
            if cli_log_path.exists():
                log_entries.extend(self._read_log_file(cli_log_path, lines // 4))
            
            # Check for error logs
            error_log_path = self.logs_path / "errors" / "error.log"
            if error_log_path.exists():
                error_entries = self._read_log_file(error_log_path, lines // 4)
                # Mark error entries
                error_entries = [f"❌ {entry}" for entry in error_entries]
                log_entries.extend(error_entries)
            
            # Sort by timestamp if possible and limit
            log_entries.sort(reverse=True)
            return log_entries[:lines]
            
        except Exception as e:
            self.logger.error(f"Error reading log files: {e}")
            return [f"Error reading logs: {str(e)}"]
    
    def _read_log_file(self, log_path: Path, lines: int) -> List[str]:
        """
        Read recent lines from a log file
        
        Args:
            log_path: Path to log file
            lines: Number of lines to read
            
        Returns:
            List of log entries
        """
        try:
            with open(log_path, 'r') as f:
                # Read all lines and get the last N
                all_lines = f.readlines()
                recent_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
                
                # Clean up lines and filter for relevant content
                cleaned_lines = []
                for line in recent_lines:
                    line = line.strip()
                    if line and not line.startswith('#'):
                        # Extract timestamp and message if possible
                        if ' - ' in line:
                            parts = line.split(' - ', 1)
                            if len(parts) == 2:
                                timestamp_part, message = parts
                                # Try to parse timestamp
                                try:
                                    from datetime import datetime
                                    # Common log timestamp formats
                                    for fmt in ['%Y-%m-%d %H:%M:%S', '%H:%M:%S', '%Y-%m-%d %H:%M:%S,%f']:
                                        try:
                                            datetime.strptime(timestamp_part.split(',')[0], fmt)
                                            cleaned_lines.append(line)
                                            break
                                        except ValueError:
                                            continue
                                    else:
                                        # If no timestamp format matches, still include the line
                                        cleaned_lines.append(line)
                                except:
                                    cleaned_lines.append(line)
                            else:
                                cleaned_lines.append(line)
                        else:
                            cleaned_lines.append(line)
                
                return cleaned_lines
                
        except Exception as e:
            self.logger.warning(f"Error reading log file {log_path}: {e}")
            return []
    
    def get_system_health_metrics(self) -> Dict[str, Any]:
        """
        Get system health metrics for monitoring
        
        Returns:
            Dictionary with system health information
        """
        try:
            import psutil
            import os
            
            # Get process information if bot is running
            bot_pid = None
            bot_memory = None
            bot_cpu = None
            
            # Look for PID file
            pid_file = Path("bot.pid")
            if pid_file.exists():
                try:
                    with open(pid_file, 'r') as f:
                        bot_pid = int(f.read().strip())
                    
                    # Get process metrics
                    if psutil.pid_exists(bot_pid):
                        process = psutil.Process(bot_pid)
                        bot_memory = process.memory_info().rss / 1024 / 1024  # MB
                        bot_cpu = process.cpu_percent()
                except:
                    bot_pid = None
            
            # Get system metrics
            system_memory = psutil.virtual_memory()
            system_cpu = psutil.cpu_percent()
            disk_usage = psutil.disk_usage('.')
            
            # Get database size if available
            db_size = None
            if self.db_manager and hasattr(self.db_manager, 'database_url'):
                if 'sqlite' in self.db_manager.database_url:
                    db_path = self.db_manager.database_url.replace('sqlite:///', '')
                    if os.path.exists(db_path):
                        db_size = os.path.getsize(db_path) / 1024 / 1024  # MB
            
            return {
                'bot_running': bot_pid is not None,
                'bot_pid': bot_pid,
                'bot_memory_mb': bot_memory,
                'bot_cpu_percent': bot_cpu,
                'system_memory_percent': system_memory.percent,
                'system_cpu_percent': system_cpu,
                'disk_free_gb': disk_usage.free / 1024 / 1024 / 1024,
                'disk_used_percent': (disk_usage.used / disk_usage.total) * 100,
                'database_size_mb': db_size,
                'database_available': self.db_available
            }
            
        except ImportError:
            self.logger.warning("psutil not available for system metrics")
            return {
                'bot_running': False,
                'database_available': self.db_available,
                'error': 'System metrics unavailable (psutil not installed)'
            }
        except Exception as e:
            self.logger.error(f"Error getting system health metrics: {e}")
            return {
                'bot_running': False,
                'database_available': self.db_available,
                'error': str(e)
            }

    def _close_orders_via_exchanges(self, session: Session, open_orders: List[OrderModel], timeout: int) -> Tuple[int, int]:
        """
        Close orders via real exchange APIs
        
        Args:
            session: Database session
            open_orders: List of open orders to close
            timeout: Timeout in seconds
            
        Returns:
            Tuple of (closed_orders, failed_orders)
        """
        try:
            # Import here to avoid circular imports
            try:
                from src.exchanges.ccxt_adapter import CCXTAdapter
            except ImportError:
                CCXTAdapter = None
            from genebot.config.manager import ConfigManager
            
            closed_orders = 0
            failed_orders = 0
            
            # Group orders by exchange
            orders_by_exchange = {}
            for order in open_orders:
                exchange = order.exchange
                if exchange not in orders_by_exchange:
                    orders_by_exchange[exchange] = []
                orders_by_exchange[exchange].append(order)
            
            # Load account configurations
            config_manager = ConfigManager()
            accounts_config = self._load_accounts_config()
            
            if not accounts_config:
                self.logger.warning("No account configurations found")
                return self._close_orders_database_only(session, open_orders)
            
            # Process each exchange
            for exchange_name, exchange_orders in orders_by_exchange.items():
                try:
                    # Find matching account configuration
                    account_config = None
                    for account_name, config in accounts_config.items():
                        if config.get('exchange', '').lower() == exchange_name.lower():
                            account_config = config
                            break
                    
                    if not account_config:
                        self.logger.warning(f"No account configuration found for exchange {exchange_name}")
                        failed_orders += len(exchange_orders)
                        continue
                    
                    # Create exchange adapter
                    adapter_config = {
                        'api_key': account_config.get('api_key', ''),
                        'secret': account_config.get('secret', ''),
                        'passphrase': account_config.get('passphrase', ''),
                        'sandbox': account_config.get('sandbox', False),
                        'test': account_config.get('test', False)
                    }
                    
                    adapter = CCXTAdapter(exchange_name, adapter_config)
                    
                    # Connect and authenticate
                    import asyncio
                    
                    async def close_exchange_orders():
                        nonlocal closed_orders, failed_orders
                        
                        try:
                            if not await adapter.connect():
                                self.logger.error(f"Failed to connect to {exchange_name}")
                                return
                            
                            if not await adapter.authenticate():
                                self.logger.error(f"Failed to authenticate with {exchange_name}")
                                await adapter.disconnect()
                                return
                            
                            # Close each order
                            for order in exchange_orders:
                                try:
                                    await adapter.cancel_order(order.order_id, order.symbol)
                                    
                                    # Update order status in database
                                    order.status = 'cancelled'
                                    order.updated_at = datetime.utcnow()
                                    closed_orders += 1
                                    
                                    self.logger.info(f"Closed order {order.order_id} for {order.symbol}")
                                    
                                except Exception as e:
                                    self.logger.error(f"Failed to close order {order.order_id}: {e}")
                                    failed_orders += 1
                            
                            await adapter.disconnect()
                            
                        except Exception as e:
                            self.logger.error(f"Error processing {exchange_name} orders: {e}")
                            failed_orders += len(exchange_orders)
                    
                    # Run async operation
                    asyncio.run(close_exchange_orders())
                    
                except Exception as e:
                    self.logger.error(f"Error setting up exchange {exchange_name}: {e}")
                    failed_orders += len(exchange_orders)
            
            # Commit database changes
            session.commit()
            
            return closed_orders, failed_orders
            
        except Exception as e:
            self.logger.error(f"Error in close orders via exchanges: {e}")
            # Fallback to database-only update
            return self._close_orders_database_only(session, open_orders)
    
    def _close_orders_database_only(self, session: Session, open_orders: List[OrderModel]) -> Tuple[int, int]:
        """
        Fallback method to update order status in database only
        
        Args:
            session: Database session
            open_orders: List of open orders
            
        Returns:
            Tuple of (closed_orders, failed_orders)
        """
        try:
            closed_orders = 0
            
            for order in open_orders:
                order.status = 'cancelled'
                order.updated_at = datetime.utcnow()
                closed_orders += 1
            
            session.commit()
            
            self.logger.warning("Orders updated in database only - no exchange API calls made")
            return closed_orders, 0
            
        except Exception as e:
            self.logger.error(f"Error updating orders in database: {e}")
            return 0, len(open_orders)

    def _load_accounts_config(self) -> Dict[str, Any]:
        """Load accounts configuration from YAML file"""
        try:
            import yaml
            
            accounts_file = Path("config") / "accounts.yaml"
            if not accounts_file.exists():
                return {}
            
            with open(accounts_file, 'r') as f:
                accounts_data = yaml.safe_load(f)
            
            # Flatten the structure for easier access
            all_accounts = {}
            
            # Add crypto exchanges
            crypto_exchanges = accounts_data.get('crypto_exchanges', {})
            for name, config in crypto_exchanges.items():
                all_accounts[name] = {
                    **config,
                    'type': 'crypto',
                    'exchange': config.get('exchange_type', 'unknown')
                }
            
            # Add forex brokers
            forex_brokers = accounts_data.get('forex_brokers', {})
            for name, config in forex_brokers.items():
                all_accounts[name] = {
                    **config,
                    'type': 'forex',
                    'exchange': config.get('broker_type', 'unknown')
                }
            
            return all_accounts
            
        except Exception as e:
            self.logger.error(f"Error loading accounts configuration: {e}")
            return {}

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit"""
        if hasattr(self, 'db_manager') and self.db_manager:
            self.db_manager.close()