"""
因子排序轮动策略。

定期按因子值排序，买入排名最高的股票（截面策略）。
"""

import pandas as pd

from backtest.base import BaseStrategy


class FactorRotationStrategy(BaseStrategy):
    """
    因子排序选股策略。

    适用于多股票截面场景：对每只股票计算因子值，
    选排名最高的 top_n 只做多。
    """

    category = "rotation"

    def __init__(self, factor_name: str, top_n: int = 5, bottom_n: int = 0):
        self.factor_name = factor_name
        self.top_n = top_n
        self.bottom_n = bottom_n
        self.name = f"rotation_{factor_name}_top{top_n}"

    def generate_signals(self, factor_df: pd.DataFrame) -> pd.Series:
        """
        单股票/截面模式：factor_df 支持两种输入方式。
        - 单股票: 对每只股票单次调用
        - 截面: 通过 run_cross_section 逐股票调用
        """
        if self.factor_name not in factor_df.columns:
            raise ValueError(f"factor_df 缺少 '{self.factor_name}' 列")

        factor = factor_df[self.factor_name]
        valid = factor.dropna()
        if len(valid) < self.top_n * 2:
            return pd.Series(-1, index=factor_df.index)

        threshold = valid.quantile(1 - self.top_n / max(len(valid), self.top_n))
        signals = pd.Series(-1, index=factor_df.index)
        signals[factor > threshold] = 1

        return signals

    def rank_stocks(
        self, factor_values: dict[str, float]
    ) -> list[str]:
        """
        对股票按因子值排序，返回 top N 的 ts_code 列表。

        参数:
            factor_values: {ts_code: factor_value}
        """
        sorted_stocks = sorted(factor_values, key=factor_values.get, reverse=True)
        return sorted_stocks[: self.top_n]
