"""Technical indicators module for calculating common trading indicators."""


import pandas as pd


def sma(data: pd.Series, period: int = 20) -> pd.Series:
    """
    Calculate Simple Moving Average (SMA).

    Args:
        data: Price series (usually close prices)
        period: Number of periods for the moving average

    Returns:
        Series containing SMA values
    """
    return data.rolling(window=period, min_periods=period).mean()


def ema(data: pd.Series, period: int = 20) -> pd.Series:
    """
    Calculate Exponential Moving Average (EMA).

    Args:
        data: Price series (usually close prices)
        period: Number of periods for the moving average

    Returns:
        Series containing EMA values
    """
    return data.ewm(span=period, adjust=False, min_periods=period).mean()


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

    Args:
        data: Price series (usually close prices)
        period: Number of periods for RSI calculation

    Returns:
        Series containing RSI values (0-100)
    """
    # Calculate price changes
    delta = data.diff()

    # Separate gains and losses
    gains = delta.where(delta > 0, 0)
    losses = (-delta).where(delta < 0, 0)

    # Calculate average gains and losses
    avg_gains = gains.ewm(span=period, adjust=False, min_periods=period).mean()
    avg_losses = losses.ewm(span=period, adjust=False, min_periods=period).mean()

    # Calculate RS and RSI
    rs = avg_gains / avg_losses
    rsi = 100 - (100 / (1 + rs))

    return rsi


def macd(
    data: pd.Series,
    fast_period: int = 12,
    slow_period: int = 26,
    signal_period: int = 9,
) -> dict[str, pd.Series]:
    """
    Calculate MACD (Moving Average Convergence Divergence).

    Args:
        data: Price series (usually close prices)
        fast_period: Fast EMA period
        slow_period: Slow EMA period
        signal_period: Signal line EMA period

    Returns:
        Dictionary with 'macd', 'signal', and 'histogram' Series
    """
    # Calculate fast and slow EMAs
    fast_ema = ema(data, fast_period)
    slow_ema = ema(data, slow_period)

    # Calculate MACD line
    macd_line = fast_ema - slow_ema

    # Calculate signal line
    signal_line = ema(macd_line, signal_period)

    # Calculate histogram
    histogram = macd_line - signal_line

    return {
        "macd": macd_line,
        "signal": signal_line,
        "histogram": histogram,
    }


def bollinger_bands(
    data: pd.Series,
    period: int = 20,
    std_dev: float = 2.0,
) -> dict[str, pd.Series]:
    """
    Calculate Bollinger Bands.

    Args:
        data: Price series (usually close prices)
        period: Number of periods for moving average
        std_dev: Number of standard deviations for bands

    Returns:
        Dictionary with 'upper', 'middle', and 'lower' Series
    """
    # Calculate middle band (SMA)
    middle = sma(data, period)

    # Calculate standard deviation
    rolling_std = data.rolling(window=period, min_periods=period).std()

    # Calculate upper and lower bands
    upper = middle + (rolling_std * std_dev)
    lower = middle - (rolling_std * std_dev)

    return {
        "upper": upper,
        "middle": middle,
        "lower": lower,
    }
