from typing import Dict
import pandas as pd
import numpy as np
from .indicators import IndicatorCalculator


class StrategyEvaluator:
    EMA_PERIODS = [5, 9, 15, 21, 30, 55, 100, 200]
    
    @staticmethod
    def _current_values(df: pd.DataFrame) -> dict:
        """Extract current values from the latest data point"""
        vals = {
            'close': df['close'].iloc[-1],
            'open': df['open'].iloc[-1],
            'high': df['high'].iloc[-1],
            'low': df['low'].iloc[-1],
            'volume': df['volume'].iloc[-1],
            'prev_close': df['close'].iloc[-2] if len(df) > 1 else None,
            'avg_volume': df['volume'].rolling(20).mean().iloc[-1] if len(df) > 20 else df['volume'].mean(),
        }
        
        # Add indicators if present
        for indicator in ['vwap', 'rsi', 'macd_hist']:
            if indicator in df.columns:
                vals[indicator] = df[indicator].iloc[-1]
        
        # Add EMA values
        ema_values = {}
        for period in StrategyEvaluator.EMA_PERIODS:
            col = f'ema_{period}'
            if col in df.columns:
                ema_values[period] = df[col].iloc[-1]
        vals['ema_stack'] = ema_values
        
        return vals

    @staticmethod
    def _calculate_targets_stop_loss(close_price, risk_reward_ratio=2, atr_period=14, df=None):
        """Calculate targets and stop loss based on volatility"""
        if df is not None and len(df) >= atr_period:
            # Calculate ATR (Average True Range)
            high_low = df['high'] - df['low']
            high_close = np.abs(df['high'] - df['close'].shift())
            low_close = np.abs(df['low'] - df['close'].shift())
            true_range = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
            atr = true_range.tail(atr_period).mean()
        else:
            # Default to 2% volatility if ATR can't be calculated
            atr = close_price * 0.02
        
        stop_loss = close_price - (atr * 1.5)
        target_1 = close_price + (atr * risk_reward_ratio)
        target_2 = close_price + (atr * risk_reward_ratio * 2)
        
        return stop_loss, target_1, target_2

    @staticmethod
    def strategy_momentum(df: pd.DataFrame) -> dict:
        vals = StrategyEvaluator._current_values(df)
        if vals['prev_close'] is None:
            return {'signal': 'HOLD', 'confidence': 0}
        
        conditions = []
        reasons = []
        
        # Price > EMAs (5, 9, 15)
        if all(period in vals['ema_stack'] for period in [5, 9, 15]):
            if vals['close'] > vals['ema_stack'][5] > vals['ema_stack'][9] > vals['ema_stack'][15]:
                conditions.append(True)
                reasons.append("Price above EMA stack")
        
        # Price > VWAP
        if 'vwap' in vals and vals['close'] > vals['vwap']:
            conditions.append(True)
            reasons.append("Price above VWAP")
        
        # RSI conditions
        if 'rsi' in vals:
            if vals['rsi'] > 55 and vals['rsi'] > df['rsi'].iloc[-2]:
                conditions.append(True)
                reasons.append("RSI > 55 and rising")
        
        # MACD histogram positive
        if 'macd_hist' in vals and vals['macd_hist'] > 0:
            conditions.append(True)
            reasons.append("MACD histogram positive")
        
        # Volume above average
        if vals['volume'] > vals['avg_volume']:
            conditions.append(True)
            reasons.append("Volume above average")
        
        # Calculate confidence
        confidence = int((len(conditions) / 5) * 100) if conditions else 0
        
        if confidence >= 70:
            stop_loss, target_1, target_2 = StrategyEvaluator._calculate_targets_stop_loss(
                vals['close'], df=df
            )
            return {
                'signal': 'BUY',
                'confidence': min(confidence, 99),
                'reason': ", ".join(reasons),
                'targets': [target_1, target_2],
                'stop_loss': stop_loss
            }
        return {'signal': 'HOLD', 'confidence': 0}

    @staticmethod
    def strategy_vwap_pullback(df: pd.DataFrame) -> dict:
        vals = StrategyEvaluator._current_values(df)
        if vals['prev_close'] is None or 'vwap' not in vals:
            return {'signal': 'HOLD', 'confidence': 0}
        
        conditions = []
        reasons = []
        
        # Uptrend condition (price above VWAP)
        if vals['close'] > vals['vwap']:
            conditions.append(True)
            reasons.append("Price in uptrend (above VWAP)")
        
        # Pullback condition (price dipped to VWAP)
        if vals['low'] <= vals['vwap'] <= vals['high']:
            conditions.append(True)
            reasons.append("Price pulled back to VWAP")
        
        # Bullish reversal candle
        if vals['close'] > vals['open'] and vals['close'] > vals['prev_close']:
            conditions.append(True)
            reasons.append("Bullish reversal candle")
        
        # Volume confirmation
        if vals['volume'] > vals['avg_volume']:
            conditions.append(True)
            reasons.append("Volume above average")
        
        confidence = int((len(conditions) / 4) * 100) if conditions else 0
        
        if confidence >= 75:
            stop_loss, target_1, target_2 = StrategyEvaluator._calculate_targets_stop_loss(
                vals['close'], df=df
            )
            return {
                'signal': 'BUY',
                'confidence': min(confidence, 99),
                'reason': ", ".join(reasons),
                'targets': [target_1, target_2],
                'stop_loss': min(vals['vwap'], stop_loss)  # Use VWAP as support
            }
        return {'signal': 'HOLD', 'confidence': 0}

    @staticmethod
    def strategy_ema_crossover(df: pd.DataFrame) -> dict:
        vals = StrategyEvaluator._current_values(df)
        if len(df) < 2 or not all(period in vals['ema_stack'] for period in [5, 9, 21]):
            return {'signal': 'HOLD', 'confidence': 0}
        
        conditions = []
        reasons = []
        
        # EMA crossover: 5 EMA crosses above 9 EMA
        ema_5_today = vals['ema_stack'][5]
        ema_5_yesterday = df['ema_5'].iloc[-2]
        ema_9_today = vals['ema_stack'][9]
        ema_9_yesterday = df['ema_9'].iloc[-2]
        
        if ema_5_today > ema_9_today and ema_5_yesterday <= ema_9_yesterday:
            conditions.append(True)
            reasons.append("5 EMA crossed above 9 EMA")
        
        # Golden cross: Shorter EMAs above longer EMAs
        if vals['ema_stack'][5] > vals['ema_stack'][9] > vals['ema_stack'][21]:
            conditions.append(True)
            reasons.append("EMA stack in bullish order")
        
        # Price above all EMAs
        if vals['close'] > vals['ema_stack'][5]:
            conditions.append(True)
            reasons.append("Price above all EMAs")
        
        # Volume confirmation
        if vals['volume'] > vals['avg_volume']:
            conditions.append(True)
            reasons.append("Volume above average")
        
        confidence = int((len(conditions) / 4) * 100) if conditions else 0
        
        if confidence >= 75:
            stop_loss, target_1, target_2 = StrategyEvaluator._calculate_targets_stop_loss(
                vals['close'], df=df
            )
            return {
                'signal': 'BUY',
                'confidence': min(confidence, 99),
                'reason': ", ".join(reasons),
                'targets': [target_1, target_2],
                'stop_loss': stop_loss
            }
        return {'signal': 'HOLD', 'confidence': 0}

    @staticmethod
    def strategy_rsi_volume_reversal(df: pd.DataFrame) -> dict:
        vals = StrategyEvaluator._current_values(df)
        if vals['prev_close'] is None or 'rsi' not in vals:
            return {'signal': 'HOLD', 'confidence': 0}
        
        conditions = []
        reasons = []
        
        # Oversold reversal
        rsi_today = vals['rsi']
        rsi_yesterday = df['rsi'].iloc[-2]
        
        if rsi_yesterday < 30 < rsi_today:
            conditions.append(True)
            reasons.append("RSI crossed above 30 from oversold")
        
        # Volume spike
        volume_ratio = vals['volume'] / vals['avg_volume'] if vals['avg_volume'] > 0 else 1
        if volume_ratio > 1.5:
            conditions.append(True)
            reasons.append(f"Volume spike ({volume_ratio:.1f}x avg)")
        
        # Bullish engulfing pattern
        if (vals['close'] > vals['open'] and  # Today is bullish
            vals['prev_close'] < df['open'].iloc[-2] and  # Yesterday was bearish
            vals['close'] > df['open'].iloc[-2] and  # Today closed above yesterday's open
            vals['open'] < vals['prev_close']):  # Today opened below yesterday's close
            conditions.append(True)
            reasons.append("Bullish engulfing pattern")
        
        confidence = int((len(conditions) / 3) * 100) if conditions else 0
        
        if confidence >= 70:
            stop_loss, target_1, target_2 = StrategyEvaluator._calculate_targets_stop_loss(
                vals['close'], df=df
            )
            return {
                'signal': 'BUY',
                'confidence': min(confidence, 99),
                'reason': ", ".join(reasons),
                'targets': [target_1, target_2],
                'stop_loss': stop_loss
            }
        return {'signal': 'HOLD', 'confidence': 0}
    

    @staticmethod
    def analyze_multi_timeframe(timeframe_data: Dict[str, pd.DataFrame], pivots: Dict[str, Dict[str, float]]) -> dict:
        """
        Analyze across all timeframes with pivot points
        """
        # Get primary daily data
        daily_df = timeframe_data.get('day')
        if daily_df is None or daily_df.empty:
            return {'signal': 'HOLD', 'confidence': 0}
        
        # Initialize conditions and reasons
        conditions = []
        reasons = []
        
        # 1. Trend Alignment (Primary Criteria)
        trend_aligned = True
        for tf in ['5min', '15min', '30min', 'day', 'week', 'month']:
            df = timeframe_data.get(tf)
            if df is not None and not df.empty:
                vals = StrategyEvaluator._current_values(df)
                # Check if price above all EMAs
                if not all(vals['close'] > vals['ema_stack'].get(f'ema_{period}', 0) 
                          for period in [5, 9, 15, 21, 30, 55, 100, 200]):
                    trend_aligned = False
                    break
                    
        if trend_aligned:
            conditions.append(True)
            reasons.append("Price above all EMAs across all timeframes")
        
        # 2. Pivot Point Analysis
        daily_pivots = pivots.get('day', {})
        if daily_pivots:
            current_close = daily_df['close'].iloc[-1]
            if current_close > daily_pivots.get('S1', 0) and current_close < daily_pivots.get('R1', float('inf')):
                conditions.append(True)
                reasons.append("Price between S1-R1 pivot range")
        
        # 3. Volume Confirmation (Multi-timeframe)
        volume_confirmed = True
        for tf in ['15min', '30min', 'day']:
            df = timeframe_data.get(tf)
            if df is not None and len(df) > 20:
                current_vol = df['volume'].iloc[-1]
                avg_vol = df['volume'].rolling(20).mean().iloc[-1]
                if current_vol < avg_vol * 0.8:  # 80% of average volume
                    volume_confirmed = False
                    break
                    
        if volume_confirmed:
            conditions.append(True)
            reasons.append("Volume confirmed across timeframes")
        
        # 4. Supertrend Analysis
        supertrend_bullish = True
        for tf in ['15min', '30min', 'day']:
            df = timeframe_data.get(tf)
            if df is not None and 'supertrend_direction' in df.columns:
                if df['supertrend_direction'].iloc[-1] != 1:  # 1 = uptrend
                    supertrend_bullish = False
                    break
                    
        if supertrend_bullish:
            conditions.append(True)
            reasons.append("Supertrend bullish across timeframes")
        
        # Calculate confidence
        confidence = int((len(conditions) / 4) * 100) if conditions else 0
        
        if confidence >= 75:
            # Calculate targets using pivot points
            stop_loss = daily_pivots.get('S1', daily_df['close'].iloc[-1] * 0.97)
            target_1 = daily_pivots.get('R1', daily_df['close'].iloc[-1] * 1.03)
            target_2 = daily_pivots.get('R2', daily_df['close'].iloc[-1] * 1.06)
            
            return {
                'signal': 'BUY',
                'confidence': confidence,
                'reason': ", ".join(reasons),
                'targets': [target_1, target_2],
                'stop_loss': stop_loss,
                'strategy_name': 'Multi-Timeframe Momentum'
            }
        
        return {'signal': 'HOLD', 'confidence': 0}

