"""
Crossover Detection Functions

PineScript-like crossover/crossunder detection for strategy signal generation.

Usage:
    from sixtysix.ta import crossover, crossunder, crossed
"""

from __future__ import annotations
from typing import Union
import pandas as pd

from .helpers import HasBarIndex


def crossover(ctx: HasBarIndex, a: pd.Series, b: Union[pd.Series, float]) -> bool:
    """
    Check if series 'a' crosses above series/value 'b' at the current bar.

    Similar to PineScript's ta.crossover().

    Args:
        ctx: Trading context (provides current bar index)
        a: First series (e.g., fast SMA)
        b: Second series or constant value (e.g., slow SMA or 0)

    Returns:
        True if 'a' crossed above 'b' at the current bar

    Example:
        if crossover(self.ctx, self.fast_sma, self.slow_sma):
            return self.buy(reason='Golden cross')
    """
    idx = ctx.bar_index

    if idx < 1:
        return False

    curr_a = a.iloc[idx]
    prev_a = a.iloc[idx - 1]

    if isinstance(b, pd.Series):
        curr_b = b.iloc[idx]
        prev_b = b.iloc[idx - 1]
    else:
        curr_b = prev_b = b

    # Check for NaN
    if pd.isna(curr_a) or pd.isna(prev_a) or pd.isna(curr_b) or pd.isna(prev_b):
        return False

    return prev_a <= prev_b and curr_a > curr_b


def crossunder(ctx: HasBarIndex, a: pd.Series, b: Union[pd.Series, float]) -> bool:
    """
    Check if series 'a' crosses below series/value 'b' at the current bar.

    Similar to PineScript's ta.crossunder().

    Args:
        ctx: Trading context (provides current bar index)
        a: First series (e.g., fast SMA)
        b: Second series or constant value (e.g., slow SMA or 0)

    Returns:
        True if 'a' crossed below 'b' at the current bar

    Example:
        if crossunder(self.ctx, self.fast_sma, self.slow_sma):
            return self.close(reason='Death cross')
    """
    idx = ctx.bar_index

    if idx < 1:
        return False

    curr_a = a.iloc[idx]
    prev_a = a.iloc[idx - 1]

    if isinstance(b, pd.Series):
        curr_b = b.iloc[idx]
        prev_b = b.iloc[idx - 1]
    else:
        curr_b = prev_b = b

    # Check for NaN
    if pd.isna(curr_a) or pd.isna(prev_a) or pd.isna(curr_b) or pd.isna(prev_b):
        return False

    return prev_a >= prev_b and curr_a < curr_b


def crossed(ctx: HasBarIndex, a: pd.Series, b: Union[pd.Series, float]) -> bool:
    """
    Check if series 'a' crossed series/value 'b' in either direction.

    Args:
        ctx: Trading context (provides current bar index)
        a: First series
        b: Second series or constant value

    Returns:
        True if 'a' crossed 'b' (either above or below)

    Example:
        if crossed(self.ctx, self.rsi, 50):
            print('RSI crossed the 50 level')
    """
    return crossover(ctx, a, b) or crossunder(ctx, a, b)
