"""
信号生成工具函数。

因子值 → 交易信号的桥梁，纯函数无副作用。
"""

import pandas as pd


def factor_to_threshold_signal(
    factor_series: pd.Series,
    buy_threshold: float,
    sell_threshold: float | None = None,
    cross_direction: str = "up",
) -> pd.Series:
    """
    因子阈值交叉信号。

    参数:
        factor_series: 因子值 Series
        buy_threshold: 买入阈值（如 RSI < 30 则买）
        sell_threshold: 卖出阈值（如 RSI > 70 则卖），None 表示平所有仓
        cross_direction: 'up'=因子向上穿越阈值时触发, 'down'=向下穿越

    返回:
        信号 Series：1=买入, 0=平仓
    """
    signals = pd.Series(0, index=factor_series.index)

    if cross_direction == "down":
        buys = factor_series < buy_threshold
    else:
        buys = factor_series > buy_threshold

    signals[buys] = 1

    if sell_threshold is not None:
        if cross_direction == "down":
            sells = factor_series > sell_threshold
        else:
            sells = factor_series < sell_threshold
        signals[sells] = 0

    # 过滤连续信号
    signals = _filter_consecutive(signals)

    return signals


def factor_to_quantile_signal(
    factor_series: pd.Series,
    top_quantile: float = 0.8,
    bottom_quantile: float = 0.2,
) -> pd.Series:
    """
    因子分位数信号 — 按滚动分位数判断。

    参数:
        factor_series: 因子值
        top_quantile: 高于此分位买入
        bottom_quantile: 低于此分位平仓

    返回:
        信号 Series
    """
    top = factor_series.quantile(top_quantile)
    bottom = factor_series.quantile(bottom_quantile)

    signals = pd.Series(0, index=factor_series.index)
    signals[factor_series > top] = 1
    signals[factor_series < bottom] = 0

    return _filter_consecutive(signals)


def cross_signal(
    fast: pd.Series,
    slow: pd.Series,
) -> pd.Series:
    """
    金叉/死叉信号。

    fast 上穿 slow → 买入(1)
    fast 下穿 slow → 平仓(0)
    """
    fast = fast.dropna()
    slow = slow.dropna()
    common_idx = fast.index.intersection(slow.index)
    fast, slow = fast[common_idx], slow[common_idx]

    signals = pd.Series(-1, index=common_idx)
    above = (fast > slow).fillna(False)
    above = above.infer_objects(copy=False)
    # 交叉点：今天 above=True 且昨天 above=False → 金叉
    prev = above.shift(1).fillna(False)
    prev = prev.infer_objects(copy=False)
    cross_up = above & ~prev
    cross_down = ~above & prev

    signals[cross_up] = 1
    signals[cross_down] = 0

    return _filter_consecutive(signals)


def _filter_consecutive(signals: pd.Series) -> pd.Series:
    """过滤连续相同信号，只保留首次出现的信号。"""
    result = signals.copy()
    prev = None
    for i in range(len(result)):
        if result.iloc[i] == prev:
            result.iloc[i] = -1  # 标记为不操作
        else:
            prev = result.iloc[i]
    return result[result != -1].reindex(signals.index).fillna(-1)
