"""Volatility Breakout Strategy - Captures explosive moves after consolidation."""

from decimal import Decimal
from typing import Dict, Any, Optional, List
import pandas as pd
import numpy as np

from ..base import BaseStrategy, StrategySignal, SignalType
from src.data.pricing_service import get_pricing_service
from src.data.indicators import get_indicators
from src.core.logger import get_logger

logger = get_logger(__name__)


class VolatilityBreakoutStrategy(BaseStrategy):
    """
    Volatility Breakout Strategy that identifies and trades breakouts from consolidation.
    
    Logic:
    1. Detect consolidation using Bollinger Band Width (squeeze).
    2. Confirm breakout when price exits the bands with volume confirmation.
    3. Use ADX to ensure the trend is strong enough to follow.
    
    Entry Conditions (BUY):
    - Bollinger Band Width < Squeeze Threshold (consolidation detected)
    - Price breaks above Upper Bollinger Band
    - Volume > 20-day average volume (confirmation)
    - ADX > 25 (strong trend)
    
    Entry Conditions (SELL):
    - Price breaks below Lower Bollinger Band
    - Volume > 20-day average volume
    - ADX > 25 (strong trend)
    """

    def __init__(self, name: str, parameters: Dict[str, Any], timeframes: List[str] = None):
        super().__init__(name, parameters, timeframes)
        
        # Strategy parameters
        self.bb_period = int(parameters.get('bb_period', 20))
        self.bb_std_dev = float(parameters.get('bb_std_dev', 2.0))
        self.squeeze_threshold = float(parameters.get('squeeze_threshold', 0.1))
        self.volume_multiplier = float(parameters.get('volume_multiplier', 1.5))
        self.adx_period = int(parameters.get('adx_period', 14))
        self.min_adx = float(parameters.get('min_adx', 25.0))
        self.use_volume_filter = parameters.get('use_volume_filter', True)
        
        self.pricing_service = get_pricing_service()
        self.indicators = get_indicators()
        
        # Track squeeze state
        self._in_squeeze = False

    async def on_tick(self, symbol: str, price: Decimal, timeframe: str, data: Dict[str, Any]) -> Optional[StrategySignal]:
        """Check for volatility breakout signals."""
        if not self.enabled:
            return None

        try:
            # Fetch OHLCV data
            ohlcv = self.pricing_service.get_ohlcv(
                symbol=symbol,
                timeframe=timeframe,
                limit=max(self.bb_period, self.adx_period) + 30
            )
            
            if not ohlcv or len(ohlcv) < self.bb_period + 10:
                return None
            
            # Convert to DataFrame
            df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
            
            # Calculate Bollinger Bands
            close = df['close'].astype(float)
            high = df['high'].astype(float)
            low = df['low'].astype(float)
            volume = df['volume'].astype(float)
            
            bb_upper, bb_middle, bb_lower = self.indicators.bollinger_bands(
                close, period=self.bb_period, std_dev=self.bb_std_dev
            )
            
            # Calculate Bollinger Band Width (squeeze indicator)
            bb_width = (bb_upper - bb_lower) / bb_middle
            current_width = bb_width.iloc[-1]
            
            # Calculate ADX for trend strength
            adx = self.indicators.adx(high, low, close, period=self.adx_period)
            current_adx = adx.iloc[-1] if not pd.isna(adx.iloc[-1]) else 0.0
            
            # Calculate volume metrics
            avg_volume = volume.rolling(window=20).mean().iloc[-1]
            current_volume = volume.iloc[-1]
            volume_ratio = current_volume / avg_volume if avg_volume > 0 else 0
            
            current_price = float(price)
            upper_band = bb_upper.iloc[-1]
            lower_band = bb_lower.iloc[-1]
            
            # Check for squeeze (consolidation)
            is_squeeze = current_width < self.squeeze_threshold
            was_in_squeeze = self._in_squeeze
            self._in_squeeze = is_squeeze
            
            self.logger.debug(
                f"Volatility Breakout {symbol}: Width={current_width:.4f}, "
                f"ADX={current_adx:.1f}, Vol Ratio={volume_ratio:.2f}, "
                f"Squeeze={is_squeeze}"
            )
            
            # No signal if not breaking out of a squeeze
            if not was_in_squeeze:
                return None
            
            # Volume filter
            if self.use_volume_filter and volume_ratio < self.volume_multiplier:
                self.logger.debug(f"Volume filter: {volume_ratio:.2f} < {self.volume_multiplier}")
                return None
            
            # ADX filter - ensure trend is strong
            if current_adx < self.min_adx:
                self.logger.debug(f"ADX filter: {current_adx:.1f} < {self.min_adx}")
                return None
            
            # Check for breakout
            signal_type = None
            
            # Bullish breakout - price breaks above upper band
            if current_price > upper_band:
                signal_type = SignalType.BUY
                self.logger.info(
                    f"BULLISH BREAKOUT: {symbol} @ {current_price:.2f} > Upper Band {upper_band:.2f}"
                )
            
            # Bearish breakout - price breaks below lower band
            elif current_price < lower_band:
                signal_type = SignalType.SELL
                self.logger.info(
                    f"BEARISH BREAKOUT: {symbol} @ {current_price:.2f} < Lower Band {lower_band:.2f}"
                )
            
            if signal_type:
                # Calculate signal strength based on multiple factors
                strength = min(1.0, (
                    (current_adx / 50) * 0.4 +  # ADX contribution
                    (volume_ratio / 3) * 0.4 +   # Volume contribution
                    0.2                           # Base strength for breakout
                ))
                
                signal = StrategySignal(
                    signal_type=signal_type,
                    symbol=symbol,
                    strength=strength,
                    price=price,
                    metadata={
                        "strategy": "volatility_breakout",
                        "bb_width": float(current_width),
                        "adx": float(current_adx),
                        "volume_ratio": float(volume_ratio),
                        "upper_band": float(upper_band),
                        "lower_band": float(lower_band),
                        "was_squeeze": was_in_squeeze,
                        "description": f"Volatility Breakout: ADX={current_adx:.1f}, Vol={volume_ratio:.1f}x"
                    }
                )
                return signal

        except Exception as e:
            self.logger.error(f"Error in VolatilityBreakoutStrategy: {e}")
            return None
            
        return None

    def on_signal(self, signal: StrategySignal) -> Optional[StrategySignal]:
        """Process signal (pass-through)."""
        return signal
