"""
Technical Indicator Functions
"""
import pandas as pd


def calc_rsi(close: pd.Series, period: int = 14) -> pd.Series:
    """
    Calculate Relative Strength Index (RSI).

    Args:
        close: Close price series
        period: RSI period (default 14)

    Returns:
        RSI values (0-100)
    """
    delta = close.diff()
    gain = delta.clip(lower=0)
    loss = -delta.clip(upper=0)
    avg_gain = gain.ewm(alpha=1 / period, min_periods=period, adjust=False).mean()
    avg_loss = loss.ewm(alpha=1 / period, min_periods=period, adjust=False).mean()
    rs = avg_gain / avg_loss
    return 100 - (100 / (1 + rs))


def calc_macd(close: pd.Series, fast=12, slow=26, signal=9):
    """
    Calculate MACD (Moving Average Convergence Divergence).

    Args:
        close: Close price series
        fast: Fast EMA period (default 12)
        slow: Slow EMA period (default 26)
        signal: Signal line period (default 9)

    Returns:
        Tuple of (macd_line, signal_line, histogram)
    """
    ema_fast = close.ewm(span=fast, adjust=False).mean()
    ema_slow = close.ewm(span=slow, adjust=False).mean()
    macd_line = ema_fast - ema_slow
    signal_line = macd_line.ewm(span=signal, adjust=False).mean()
    histogram = macd_line - signal_line
    return macd_line, signal_line, histogram


def calc_bollinger(close: pd.Series, period=20, num_std=2):
    """
    Calculate Bollinger Bands.

    Args:
        close: Close price series
        period: SMA period (default 20)
        num_std: Number of standard deviations (default 2)

    Returns:
        Tuple of (sma, upper_band, lower_band)
    """
    sma = close.rolling(window=period).mean()
    std = close.rolling(window=period).std()
    upper = sma + num_std * std
    lower = sma - num_std * std
    return sma, upper, lower


def calc_fibonacci_levels(df: pd.DataFrame, period: int = 60, fib_levels: list = None) -> dict:
    """
    Calculate Fibonacci Retracement levels dari highest high dan lowest low
    dalam period tertentu.

    Args:
        df: DataFrame dengan 'High' dan 'Low' columns
        period: Period untuk cari high/low (default 60)
        fib_levels: List of Fibonacci levels (default [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1])

    Returns:
        Dict dengan keys: 'high', 'low', 'period', 'levels'
    """
    if fib_levels is None:
        fib_levels = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1]

    if len(df) < period:
        return {}

    # Ambil data dari period terakhir
    lookback_df = df.tail(period)

    high_price = lookback_df['High'].max()
    low_price = lookback_df['Low'].min()
    diff = high_price - low_price

    # Ensure diff is a scalar value
    if hasattr(diff, 'item'):
        diff = diff.item()
    if diff <= 0:
        return {}

    # Calculate Fibonacci levels
    levels = {}
    for level_pct in fib_levels:
        # Level dari atas ke bawah (0% di high, 100% di low)
        level_price = high_price - (diff * level_pct)
        levels[f"{level_pct*100:.1f}%"] = level_price

    return {
        'high': high_price,
        'low': low_price,
        'period': period,
        'levels': levels
    }


def calc_stochastic_rsi(rsi: pd.Series, period=14, smooth_k=3, smooth_d=3):
    """
    Stochastic RSI: 'stochastic dari RSI' - lebih sensitif daripada RSI biasa,
    bagus buat nangkep titik balik oversold/overbought yang lebih presisi.
    Skala 0-100 (bukan 0-1) biar konsisten sama style StochRSI di TradingView.

    Args:
        rsi: RSI values series
        period: Stochastic period (default 14)
        smooth_k: K smoothing period (default 3)
        smooth_d: D smoothing period (default 3)

    Returns:
        Tuple of (%K, %D)
    """
    min_rsi = rsi.rolling(window=period).min()
    max_rsi = rsi.rolling(window=period).max()
    stoch = (rsi - min_rsi) / (max_rsi - min_rsi) * 100
    k = stoch.rolling(window=smooth_k).mean()
    d = k.rolling(window=smooth_d).mean()
    return k, d
