"""Multi-indicator confirmation strategy.

This strategy requires multiple indicators (RSI, MACD, Moving Average) to align
before generating a signal, reducing false signals significantly.
"""

from decimal import Decimal
from typing import Optional, Dict, Any, List
import pandas as pd
from src.strategies.base import BaseStrategy, StrategySignal, SignalType
from src.data.indicators import get_indicators
from src.core.logger import get_logger

logger = get_logger(__name__)


class ConfirmedStrategy(BaseStrategy):
    """Multi-indicator confirmation strategy.
    
    Combines RSI, MACD, and Moving Average signals and only generates
    signals when a configurable number of indicators agree.
    """
    
    def __init__(self, name: str, parameters: Optional[Dict[str, Any]] = None, timeframes: Optional[list] = None):
        """Initialize confirmed strategy.
        
        Parameters:
            rsi_period: RSI period (default 14)
            rsi_oversold: RSI oversold threshold (default 30)
            rsi_overbought: RSI overbought threshold (default 70)
            macd_fast: MACD fast period (default 12)
            macd_slow: MACD slow period (default 26)
            macd_signal: MACD signal period (default 9)
            ma_fast: Fast MA period (default 10)
            ma_slow: Slow MA period (default 30)
            ma_type: MA type - 'sma' or 'ema' (default 'ema')
            min_confirmations: Minimum number of indicators that must agree (default 2)
            require_rsi: Require RSI confirmation (default True)
            require_macd: Require MACD confirmation (default True)
            require_ma: Require MA confirmation (default True)
        """
        super().__init__(name, parameters, timeframes)
        
        # RSI parameters
        self.rsi_period = self.parameters.get('rsi_period', 14)
        self.rsi_oversold = self.parameters.get('rsi_oversold', 30)
        self.rsi_overbought = self.parameters.get('rsi_overbought', 70)
        
        # MACD parameters
        self.macd_fast = self.parameters.get('macd_fast', 12)
        self.macd_slow = self.parameters.get('macd_slow', 26)
        self.macd_signal = self.parameters.get('macd_signal', 9)
        
        # MA parameters
        self.ma_fast = self.parameters.get('ma_fast', 10)
        self.ma_slow = self.parameters.get('ma_slow', 30)
        self.ma_type = self.parameters.get('ma_type', 'ema')
        
        # Confirmation parameters
        self.min_confirmations = self.parameters.get('min_confirmations', 2)
        self.require_rsi = self.parameters.get('require_rsi', True)
        self.require_macd = self.parameters.get('require_macd', True)
        self.require_ma = self.parameters.get('require_ma', True)
        
        self.indicators = get_indicators()
        self._price_history: List[float] = []
    
    def _check_rsi_signal(self, prices: pd.Series) -> Optional[SignalType]:
        """Check RSI for signal.
        
        Args:
            prices: Price series
            
        Returns:
            SignalType if RSI indicates signal, None otherwise
        """
        if len(prices) < self.rsi_period + 1:
            return None
        
        rsi = self.indicators.rsi(prices, self.rsi_period)
        if len(rsi) == 0:
            return None
        
        current_rsi = rsi.iloc[-1]
        
        if current_rsi < self.rsi_oversold:
            return SignalType.BUY
        elif current_rsi > self.rsi_overbought:
            return SignalType.SELL
        
        return None
    
    def _check_macd_signal(self, prices: pd.Series) -> Optional[SignalType]:
        """Check MACD for signal.
        
        Args:
            prices: Price series
            
        Returns:
            SignalType if MACD indicates signal, None otherwise
        """
        if len(prices) < self.macd_slow + self.macd_signal:
            return None
        
        macd_data = self.indicators.macd(prices, self.macd_fast, self.macd_slow, self.macd_signal)
        
        if len(macd_data['macd']) < 2:
            return None
        
        macd = macd_data['macd'].iloc[-1]
        signal_line = macd_data['signal'].iloc[-1]
        prev_macd = macd_data['macd'].iloc[-2]
        prev_signal = macd_data['signal'].iloc[-2]
        
        # Bullish crossover
        if prev_macd <= prev_signal and macd > signal_line:
            return SignalType.BUY
        # Bearish crossover
        elif prev_macd >= prev_signal and macd < signal_line:
            return SignalType.SELL
        
        return None
    
    def _check_ma_signal(self, prices: pd.Series) -> Optional[SignalType]:
        """Check Moving Average for signal.
        
        Args:
            prices: Price series
            
        Returns:
            SignalType if MA indicates signal, None otherwise
        """
        if len(prices) < self.ma_slow + 1:
            return None
        
        if self.ma_type == 'sma':
            fast_ma = self.indicators.sma(prices, self.ma_fast)
            slow_ma = self.indicators.sma(prices, self.ma_slow)
        else:
            fast_ma = self.indicators.ema(prices, self.ma_fast)
            slow_ma = self.indicators.ema(prices, self.ma_slow)
        
        if len(fast_ma) < 2 or len(slow_ma) < 2:
            return None
        
        fast_current = fast_ma.iloc[-1]
        fast_prev = fast_ma.iloc[-2]
        slow_current = slow_ma.iloc[-1]
        slow_prev = slow_ma.iloc[-2]
        
        # Bullish crossover
        if fast_prev <= slow_prev and fast_current > slow_current:
            return SignalType.BUY
        # Bearish crossover
        elif fast_prev >= slow_prev and fast_current < slow_current:
            return SignalType.SELL
        
        return None
    
    async def on_tick(self, symbol: str, price: Decimal, timeframe: str, data: Dict[str, Any]) -> Optional[StrategySignal]:
        """Generate signal based on multi-indicator confirmation."""
        # Add price to history
        self._price_history.append(float(price))
        
        # Determine minimum required data points
        max_period = max(
            self.rsi_period + 1,
            self.macd_slow + self.macd_signal,
            self.ma_slow + 1
        )
        
        if len(self._price_history) < max_period:
            return None
        
        prices = pd.Series(self._price_history[-max_period:])
        
        # Collect signals from each indicator
        signals: List[SignalType] = []
        signal_metadata: Dict[str, Any] = {}
        
        # Check RSI
        if self.require_rsi:
            rsi_signal = self._check_rsi_signal(prices)
            if rsi_signal:
                signals.append(rsi_signal)
                signal_metadata['rsi'] = rsi_signal.value
        
        # Check MACD
        if self.require_macd:
            macd_signal = self._check_macd_signal(prices)
            if macd_signal:
                signals.append(macd_signal)
                signal_metadata['macd'] = macd_signal.value
        
        # Check MA
        if self.require_ma:
            ma_signal = self._check_ma_signal(prices)
            if ma_signal:
                signals.append(ma_signal)
                signal_metadata['ma'] = ma_signal.value
        
        # Count confirmations for each signal type
        buy_count = signals.count(SignalType.BUY)
        sell_count = signals.count(SignalType.SELL)
        
        # Determine final signal based on confirmations
        final_signal = None
        confirmation_count = 0
        
        if buy_count >= self.min_confirmations:
            final_signal = SignalType.BUY
            confirmation_count = buy_count
        elif sell_count >= self.min_confirmations:
            final_signal = SignalType.SELL
            confirmation_count = sell_count
        
        if final_signal is None:
            return None
        
        # Calculate signal strength based on number of confirmations
        max_possible = sum([self.require_rsi, self.require_macd, self.require_ma])
        strength = min(1.0, confirmation_count / max_possible) if max_possible > 0 else 0.5
        
        return StrategySignal(
            signal_type=final_signal,
            symbol=symbol,
            strength=strength,
            price=price,
            metadata={
                'confirmation_count': confirmation_count,
                'max_confirmations': max_possible,
                'signals': signal_metadata,
                'strategy': 'confirmed',
                'rsi_period': self.rsi_period,
                'macd_fast': self.macd_fast,
                'macd_slow': self.macd_slow,
                'ma_type': self.ma_type,
                'ma_fast': self.ma_fast,
                'ma_slow': self.ma_slow
            }
        )
    
    def on_signal(self, signal: StrategySignal) -> Optional[StrategySignal]:
        """Process signal."""
        return signal if self.should_execute(signal) else None

