"""
AkDevz AI Market Intelligence — Quantitative Volume Analytics Engine
Calculates RVOL (Relative Volume), Volume Moving Averages, OBV, MFI, and Volume Divergence.
"""
import numpy as np
from typing import Dict, Any, Tuple

class VolumeEngine:
    @staticmethod
    def calculate_rvol(volume: np.ndarray, lookback: int = 20) -> float:
        """Calculates Relative Volume (Current volume vs Lookback SMA)."""
        if len(volume) < lookback + 1:
            return 1.0
        avg_vol = float(np.mean(volume[-lookback-1:-1]))
        if avg_vol <= 0:
            return 1.0
        return float(volume[-1] / avg_vol)

    @staticmethod
    def calculate_obv(close: np.ndarray, volume: np.ndarray) -> np.ndarray:
        """On-Balance Volume (OBV)."""
        n = len(close)
        obv = np.zeros(n, dtype=float)
        for i in range(1, n):
            if close[i] > close[i-1]:
                obv[i] = obv[i-1] + volume[i]
            elif close[i] < close[i-1]:
                obv[i] = obv[i-1] - volume[i]
            else:
                obv[i] = obv[i-1]
        return obv

    @staticmethod
    def calculate_mfi(high: np.ndarray, low: np.ndarray, close: np.ndarray, volume: np.ndarray, period: int = 14) -> np.ndarray:
        """Money Flow Index (MFI)."""
        n = len(close)
        mfi = np.full(n, np.nan, dtype=float)
        if n < period + 1:
            return mfi

        typical_price = (high + low + close) / 3.0
        raw_money_flow = typical_price * volume

        pos_flow = np.zeros(n, dtype=float)
        neg_flow = np.zeros(n, dtype=float)

        for i in range(1, n):
            if typical_price[i] > typical_price[i-1]:
                pos_flow[i] = raw_money_flow[i]
            elif typical_price[i] < typical_price[i-1]:
                neg_flow[i] = raw_money_flow[i]

        for i in range(period, n):
            pos_sum = np.sum(pos_flow[i-period+1:i+1])
            neg_sum = np.sum(neg_flow[i-period+1:i+1])

            if neg_sum == 0:
                mfi[i] = 100.0
            else:
                mr = pos_sum / neg_sum
                mfi[i] = 100.0 - (100.0 / (1.0 + mr))

        return mfi

    @staticmethod
    def detect_volume_divergence(close: np.ndarray, volume: np.ndarray, lookback: int = 15) -> Dict[str, Any]:
        """
        Detects volume divergence:
        - Bearish Divergence: Price making higher high but volume declining
        - Bullish Divergence: Price making lower low with drying volume (selling exhaustion)
        """
        if len(close) < lookback:
            return {"divergence": "NONE", "description": "Insufficient data for volume divergence"}

        recent_close = close[-lookback:]
        recent_vol = volume[-lookback:]

        price_slope = float(np.polyfit(np.arange(lookback), recent_close, 1)[0])
        vol_slope = float(np.polyfit(np.arange(lookback), recent_vol, 1)[0])

        if price_slope > 0 and vol_slope < 0:
            return {
                "divergence": "BEARISH_VOLUME_EXHAUSTION",
                "description": "Price expanding upward while volume is systematically drying up. High risk of false breakout."
            }
        elif price_slope < 0 and vol_slope < 0:
            return {
                "divergence": "BULLISH_SELLING_EXHAUSTION",
                "description": "Price moving lower while selling volume is diminishing. Potential absorption base."
            }

        return {
            "divergence": "CONGRUENT",
            "description": "Volume is confirming price movement directionally."
        }
