"""Simple Moving Average Crossover Strategy.

A classic trend-following strategy that generates signals based on
the crossover of fast and slow moving averages.

Strategy Logic:
- BUY when fast MA crosses above slow MA (golden cross)
- SELL when fast MA crosses below slow MA (death cross)
- HOLD when no crossover detected

Configuration:
- fast_period: Period for fast MA (default: 10)
- slow_period: Period for slow MA (default: 30)
- ma_type: Type of moving average ('sma', 'ema', 'wma')
- min_confidence: Minimum confidence to generate signal
"""

import numpy as np
from typing import Optional, List, Dict, Any
from .interface import Strategy, TradingDecision
from enums import Signal


class SimpleMACrossover(Strategy):
    """Simple Moving Average Crossover Strategy."""
    
    id = "simple_ma_crossover"
    name = "Simple MA Crossover"
    version = "1.0.0"
    description = "Trend-following strategy using MA crossovers"
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        """Initialize strategy.
        
        Args:
            config: Strategy configuration
                - fast_period: Fast MA period (default: 10)
                - slow_period: Slow MA period (default: 30)
                - ma_type: MA type - 'sma', 'ema', 'wma' (default: 'sma')
                - min_confidence: Minimum confidence (default: 0.5)
        """
        super().__init__(config)
        
        # Configuration with defaults
        self.fast_period = self.config.get('fast_period', 10)
        self.slow_period = self.config.get('slow_period', 30)
        self.ma_type = self.config.get('ma_type', 'sma').lower()
        self.min_confidence = self.config.get('min_confidence', 0.5)
        
        # Validate periods
        if self.fast_period >= self.slow_period:
            raise ValueError(
                f"fast_period ({self.fast_period}) must be < slow_period ({self.slow_period})"
            )
        
        # State
        self._last_fast_ma = None
        self._last_slow_ma = None
    
    async def analyze(
        self,
        ohlcv: List[Dict[str, float]],
        current_price: float,
        context: Optional[Dict[str, Any]] = None
    ) -> TradingDecision:
        """Analyze OHLCV data for MA crossover signals.
        
        Args:
            ohlcv: List of OHLCV candles with 'close' and 'timestamp'
            current_price: Current market price
            context: Additional context
            
        Returns:
            Trading decision based on MA crossover
        """
        if len(ohlcv) < self.slow_period + 1:
            # Not enough data
            return TradingDecision(
                signal=Signal.HOLD,
                confidence=0.0,
                reason=f"Not enough data (need {self.slow_period + 1} candles, have {len(ohlcv)})"
            )
        
        # Extract closing prices
        closes = [c['close'] for c in ohlcv]
        
        # Calculate moving averages
        fast_ma = self._calculate_ma(closes, self.fast_period)
        slow_ma = self._calculate_ma(closes, self.slow_period)
        
        if len(fast_ma) < 2 or len(slow_ma) < 2:
            return TradingDecision(
                signal=Signal.HOLD,
                confidence=0.0,
                reason="Not enough MA data"
            )
        
        # Get current and previous MA values
        current_fast = fast_ma[-1]
        current_slow = slow_ma[-1]
        prev_fast = fast_ma[-2]
        prev_slow = slow_ma[-2]
        
        # Detect crossover
        signal = Signal.HOLD
        confidence = 0.0
        reason = ""
        
        # Golden cross: fast MA crosses above slow MA
        if prev_fast <= prev_slow and current_fast > current_slow:
            signal = Signal.BUY
            confidence = self._calculate_confidence(current_fast, current_slow)
            reason = f"Golden cross: Fast MA ({current_fast:.2f}) crossed above Slow MA ({current_slow:.2f})"
        
        # Death cross: fast MA crosses below slow MA
        elif prev_fast >= prev_slow and current_fast < current_slow:
            signal = Signal.SELL
            confidence = self._calculate_confidence(current_fast, current_slow)
            reason = f"Death cross: Fast MA ({current_fast:.2f}) crossed below Slow MA ({current_slow:.2f})"
        
        # Trend continuation
        elif current_fast > current_slow:
            signal = Signal.HOLD
            confidence = min(0.8, (current_fast - current_slow) / current_slow)
            reason = f"Uptrend: Fast MA ({current_fast:.2f}) above Slow MA ({current_slow:.2f})"
        
        elif current_fast < current_slow:
            signal = Signal.HOLD
            confidence = min(0.8, (current_slow - current_fast) / current_slow)
            reason = f"Downtrend: Fast MA ({current_fast:.2f}) below Slow MA ({current_slow:.2f})"
        
        # Store for next iteration
        self._last_fast_ma = current_fast
        self._last_slow_ma = current_slow
        
        # Filter by minimum confidence
        if confidence < self.min_confidence:
            return TradingDecision(
                signal=Signal.HOLD,
                confidence=confidence,
                reason=f"Signal confidence ({confidence:.2f}) below threshold ({self.min_confidence})"
            )
        
        return TradingDecision(
            signal=signal,
            confidence=confidence,
            price=current_price,
            reason=reason,
            metadata={
                'fast_ma': current_fast,
                'slow_ma': current_slow,
                'current_price': current_price,
            }
        )
    
    def _calculate_ma(self, prices: List[float], period: int, ma_type: str = None) -> List[float]:
        """Calculate moving average.
        
        Args:
            prices: List of prices
            period: MA period
            ma_type: Type of MA ('sma', 'ema', 'wma')
            
        Returns:
            List of MA values
        """
        ma_type = ma_type or self.ma_type
        
        if ma_type == 'sma':
            return self._sma(prices, period)
        elif ma_type == 'ema':
            return self._ema(prices, period)
        elif ma_type == 'wma':
            return self._wma(prices, period)
        else:
            raise ValueError(f"Unknown MA type: {ma_type}")
    
    def _sma(self, prices: List[float], period: int) -> List[float]:
        """Simple Moving Average."""
        result = []
        for i in range(len(prices)):
            if i < period - 1:
                result.append(None)
            else:
                avg = sum(prices[i - period + 1:i + 1]) / period
                result.append(avg)
        return result
    
    def _ema(self, prices: List[float], period: int) -> List[float]:
        """Exponential Moving Average."""
        result = []
        multiplier = 2 / (period + 1)
        
        # Start with SMA
        if len(prices) >= period:
            sma = sum(prices[:period]) / period
            result.extend([None] * (period - 1))
            result.append(sma)
            
            # Calculate EMA
            for price in prices[period:]:
                ema = (price - result[-1]) * multiplier + result[-1]
                result.append(ema)
        else:
            result.extend([None] * len(prices))
        
        return result
    
    def _wma(self, prices: List[float], period: int) -> List[float]:
        """Weighted Moving Average."""
        result = []
        weights = list(range(1, period + 1))
        weight_sum = sum(weights)
        
        for i in range(len(prices)):
            if i < period - 1:
                result.append(None)
            else:
                window = prices[i - period + 1:i + 1]
                wma = sum(w * p for w, p in zip(weights, window)) / weight_sum
                result.append(wma)
        
        return result
    
    def _calculate_confidence(self, fast_ma: float, slow_ma: float) -> float:
        """Calculate signal confidence based on MA separation.
        
        Confidence increases with the percentage difference between MAs.
        """
        separation = abs(fast_ma - slow_ma) / slow_ma
        # Cap confidence at 0.95
        return min(0.95, 0.5 + separation * 2)
    
    def get_indicators(self) -> List[str]:
        """List indicators used by this strategy."""
        return [f"MA({self.fast_period})", f"MA({self.slow_period})"]
    
    def validate(self) -> bool:
        """Validate strategy configuration."""
        if self.fast_period < 1:
            raise ValueError("fast_period must be >= 1")
        if self.slow_period < 1:
            raise ValueError("slow_period must be >= 1")
        if self.fast_period >= self.slow_period:
            raise ValueError("fast_period must be < slow_period")
        if self.ma_type not in ['sma', 'ema', 'wma']:
            raise ValueError(f"Invalid ma_type: {self.ma_type}")
        if not 0 <= self.min_confidence <= 1:
            raise ValueError("min_confidence must be between 0 and 1")
        return True
