"""
Dealer-Aware Flow Context Service
Tracks dealer hedging pressure, gamma exposure, and flow continuation patterns
"""
import pandas as pd
import numpy as np
from typing import Dict, Optional
from datetime import timedelta
from utils.logger import logger


class DealerFlowContext:
    """
    Analyzes flow from dealer perspective:
    - Net gamma exposure per symbol
    - Gamma flip proximity (when dealers become long/short gamma)
    - Dealer hedge pressure (forced hedging activity)
    """
    
    def __init__(self):
        # Configuration
        self.analysis_window_minutes = 120  # Look back window for gamma tracking
        self.gamma_flip_threshold = 0.3  # Gamma flip when net gamma crosses threshold
        
    def calculate_net_gamma_exposure_per_symbol(
        self,
        df: pd.DataFrame,
        symbol: str,
        timestamp: pd.Timestamp
    ) -> float:
        """
        Calculate net gamma exposure for a symbol at a given time.
        Sums all gamma exposures from recent flow.
        
        Positive = dealers are long gamma (hedging by selling on rallies, buying on dips)
        Negative = dealers are short gamma (hedging by buying on rallies, selling on dips)
        """
        if df.empty:
            return 0.0
        
        # Look at flow up to this timestamp
        window_start = timestamp - timedelta(minutes=self.analysis_window_minutes)
        
        mask = (
            (df['symbol_norm'] == symbol.upper()) &
            (df['flow_ts_utc'] >= window_start) &
            (df['flow_ts_utc'] <= timestamp) &
            (df['gamma_exposure'].notna())
        )
        
        recent_flow = df[mask]
        
        if recent_flow.empty:
            return 0.0
        
        # Sum gamma exposures
        net_gamma = recent_flow['gamma_exposure'].sum()
        
        return float(net_gamma)
    
    def calculate_gamma_flip_proximity(
        self,
        df: pd.DataFrame,
        row_idx: int
    ) -> Optional[float]:
        """
        Calculate proximity to gamma flip (when dealers switch from long to short gamma or vice versa).
        
        Returns: -1.0 to 1.0
        - Positive = approaching long gamma (dealers becoming volatility buyers)
        - Negative = approaching short gamma (dealers becoming volatility sellers)
        - 0.0 = near flip point
        """
        if row_idx >= len(df):
            return None
        
        current_row = df.iloc[row_idx]
        symbol = current_row.get('symbol_norm')
        flow_ts_utc = current_row.get('flow_ts_utc')
        gamma_exposure = current_row.get('gamma_exposure', 0) or 0
        
        if pd.isna(symbol) or pd.isna(flow_ts_utc):
            return None
        
        # Calculate current net gamma
        net_gamma = self.calculate_net_gamma_exposure_per_symbol(df, symbol, flow_ts_utc)
        
        # Normalize to -1 to 1 scale
        # Use exponential scaling to emphasize near-flip conditions
        if net_gamma == 0:
            return 0.0
        
        # Simple normalization: divide by a large threshold
        # More sophisticated: use percentile or adaptive scaling
        threshold = 1000000000  # 1B in gamma exposure as normalization factor
        normalized = net_gamma / threshold
        
        # Clamp to -1 to 1
        normalized = max(-1.0, min(1.0, normalized))
        
        # Invert: negative normalized = positive proximity (approaching long gamma)
        # This is because dealer short gamma (negative) means they're selling volatility
        return float(-normalized)
    
    def calculate_dealer_hedge_pressure_score(
        self,
        df: pd.DataFrame,
        row_idx: int
    ) -> float:
        """
        Calculate dealer hedge pressure score (0-100).
        
        Higher score = more forced hedging by dealers:
        - High net gamma exposure (dealers must hedge)
        - Recent flow creating gamma imbalance
        - Flow continuation (dealers hedging creates more flow)
        """
        if row_idx >= len(df):
            return 0.0
        
        current_row = df.iloc[row_idx]
        symbol = current_row.get('symbol_norm')
        flow_ts_utc = current_row.get('flow_ts_utc')
        gamma_exposure = current_row.get('gamma_exposure', 0) or 0
        
        if pd.isna(symbol) or pd.isna(flow_ts_utc):
            return 0.0
        
        score = 0.0
        
        # Net gamma component (0-40 points)
        # High absolute net gamma = more hedge pressure
        net_gamma = abs(self.calculate_net_gamma_exposure_per_symbol(df, symbol, flow_ts_utc))
        if net_gamma > 0:
            # Normalize: 500M = 20 points, 1B = 40 points
            normalized_gamma = min(1.0, net_gamma / 1000000000)  # 1B threshold
            score += normalized_gamma * 40.0
        
        # Recent gamma accumulation (0-30 points)
        # Recent flow creating gamma imbalance
        window_start = flow_ts_utc - timedelta(minutes=30)
        mask = (
            (df['symbol_norm'] == symbol.upper()) &
            (df['flow_ts_utc'] >= window_start) &
            (df['flow_ts_utc'] <= flow_ts_utc) &
            (df['gamma_exposure'].notna())
        )
        recent_gamma = df[mask]['gamma_exposure'].sum()
        
        if abs(recent_gamma) > 0:
            # Normalize recent gamma accumulation
            normalized_recent = min(1.0, abs(recent_gamma) / 500000000)  # 500M threshold
            score += normalized_recent * 30.0
        
        # Flow continuation component (0-30 points)
        # If flow is continuing in same direction, dealers are likely hedging
        follow_on_ratio = current_row.get('follow_on_ratio')
        if follow_on_ratio is not None and not pd.isna(follow_on_ratio):
            # High follow-on ratio = continuation = hedge pressure
            score += follow_on_ratio * 30.0
        
        return min(100.0, max(0.0, score))
    
    def validate_flow_continuation(
        self,
        df: pd.DataFrame,
        row_idx: int
    ) -> bool:
        """
        Validate if flow continuation is likely based on dealer hedge pressure.
        Returns True if continuation is expected (dealers forced to hedge).
        """
        current_row = df.iloc[row_idx]
        dealer_pressure = current_row.get('dealer_hedge_pressure_score', 0) or 0
        net_gamma = current_row.get('net_gamma_exposure_per_symbol', 0) or 0
        
        # High dealer pressure + significant gamma exposure = continuation likely
        if dealer_pressure > 50.0 and abs(net_gamma) > 100000000:  # 100M threshold
            return True
        
        return False
    
    def validate_flow_reversal(
        self,
        df: pd.DataFrame,
        row_idx: int
    ) -> bool:
        """
        Validate if flow reversal is likely.
        Reversal happens when:
        - Dealers finish hedging (gamma exposure neutralizes)
        - Price fails at key levels (VWAP, opening range)
        - Flow shows distribution pattern (decreasing premium, widening gaps)
        """
        current_row = df.iloc[row_idx]
        dealer_pressure = current_row.get('dealer_hedge_pressure_score', 0) or 0
        follow_on_ratio = current_row.get('follow_on_ratio')
        flow_acceleration = current_row.get('flow_acceleration')
        
        # Low dealer pressure + low follow-on ratio = reversal likely
        if dealer_pressure < 30.0:
            if follow_on_ratio is not None and follow_on_ratio < 0.3:
                return True
        
        # Negative flow acceleration = flow weakening = reversal
        if flow_acceleration is not None and flow_acceleration < -10000:
            return True
        
        return False
    
    def enrich_with_dealer_context(self, df: pd.DataFrame) -> pd.DataFrame:
        """
        Add dealer-aware flow context metrics to DataFrame.
        Adds: net_gamma_exposure_per_symbol, gamma_flip_proximity, dealer_hedge_pressure_score
        """
        if df.empty:
            return df
        
        df = df.copy()
        
        # Initialize columns
        df['net_gamma_exposure_per_symbol'] = 0.0
        df['gamma_flip_proximity'] = None
        df['dealer_hedge_pressure_score'] = 0.0
        
        # Sort by timestamp for proper gamma tracking
        df_sorted = df.sort_values('flow_ts_utc').reset_index(drop=True)
        
        # Calculate metrics for each row
        for idx in df_sorted.index:
            original_idx = df_sorted.index[idx]
            row = df_sorted.iloc[idx]
            
            symbol = row.get('symbol_norm')
            flow_ts_utc = row.get('flow_ts_utc')
            
            if pd.notna(symbol) and pd.notna(flow_ts_utc):
                # Net gamma exposure
                net_gamma = self.calculate_net_gamma_exposure_per_symbol(
                    df_sorted, symbol, flow_ts_utc
                )
                df.at[original_idx, 'net_gamma_exposure_per_symbol'] = float(net_gamma)
                
                # Gamma flip proximity
                flip_prox = self.calculate_gamma_flip_proximity(df_sorted, idx)
                if flip_prox is not None:
                    df.at[original_idx, 'gamma_flip_proximity'] = float(flip_prox)
                
                # Dealer hedge pressure
                pressure = self.calculate_dealer_hedge_pressure_score(df_sorted, idx)
                df.at[original_idx, 'dealer_hedge_pressure_score'] = float(pressure)
        
        logger.info(f"Dealer context enrichment complete. Mean pressure: {df['dealer_hedge_pressure_score'].mean():.2f}")
        
        return df

