"""
因子注册表。

通过名称获取因子实例，方便回测和策略配置时引用。
"""

from factors.base import BaseFactor
from factors.technical.momentum import MomentumFactor
from factors.technical.rsi import RSIFactor
from factors.technical.macd import MACDFactor
from factors.technical.volume import VolumeFactor, VolumeChangeFactor
from factors.technical.bollinger import BollingerFactor, BollingerWidthFactor
from factors.technical.atr import ATRFactor, ATRRatioFactor
from factors.technical.ma_cross import MACrossFactor, MADeviationFactor
from factors.technical.volatility import VolatilityFactor, DownsideVolatilityFactor
from factors.technical.turnover import TurnoverFactor, TurnoverChangeFactor
from factors.technical.amplitude import AmplitudeFactor
from factors.fundamental.roe import ROEFactor
from factors.fundamental.pe_pb import PEFactor, PBFactor, EPFactor
from factors.sentiment.sentiment_factor import (
    NewsSentimentFactor,
    SentimentMomentumFactor,
    SentimentConfidenceFactor,
)

# ── 内置因子工厂函数 ──────────────────────────────────────

_BUILTIN_FACTORIES: dict[str, callable] = {  # type: ignore
    # 动量
    "momentum_5": lambda: MomentumFactor(period=5),
    "momentum_10": lambda: MomentumFactor(period=10),
    "momentum_20": lambda: MomentumFactor(period=20),
    "momentum_60": lambda: MomentumFactor(period=60),
    # RSI
    "rsi_7": lambda: RSIFactor(period=7),
    "rsi_14": lambda: RSIFactor(period=14),
    # MACD
    "macd": lambda: MACDFactor(),
    "macd_5_35_5": lambda: MACDFactor(fast=5, slow=35, signal=5),
    # 量价
    "vol_ratio_5": lambda: VolumeFactor(period=5),
    "vol_ratio_20": lambda: VolumeFactor(period=20),
    "vol_chg_5": lambda: VolumeChangeFactor(period=5),
    # 布林
    "boll": lambda: BollingerFactor(),
    "boll_width": lambda: BollingerWidthFactor(),
    # ATR
    "atr_14": lambda: ATRFactor(period=14),
    "atr_ratio_14": lambda: ATRRatioFactor(period=14),
    # 均线
    "ma_cross_5_20": lambda: MACrossFactor(fast=5, slow=20),
    "ma_cross_10_60": lambda: MACrossFactor(fast=10, slow=60),
    "ma_dev_20": lambda: MADeviationFactor(period=20),
    "ma_dev_60": lambda: MADeviationFactor(period=60),
    # 波动率
    "volatility_20": lambda: VolatilityFactor(period=20),
    "volatility_60": lambda: VolatilityFactor(period=60),
    "down_vol_20": lambda: DownsideVolatilityFactor(period=20),
    # 换手率
    "turnover_5": lambda: TurnoverFactor(period=5),
    "turnover_chg_5": lambda: TurnoverChangeFactor(period=5),
    # 振幅
    "amplitude_5": lambda: AmplitudeFactor(period=5),
    "amplitude_20": lambda: AmplitudeFactor(period=20),
    # 基本面
    "roe": lambda: ROEFactor(),
    "pe": lambda: PEFactor(),
    "pb": lambda: PBFactor(),
    "ep": lambda: EPFactor(),
    # 情绪
    "news_sent_5": lambda: NewsSentimentFactor(window=5),
    "news_sent_20": lambda: NewsSentimentFactor(window=20),
    "news_conf_5": lambda: SentimentConfidenceFactor(window=5),
    "sent_delta_5": lambda: SentimentMomentumFactor(period=5),
}

# ── 分类映射 ──────────────────────────────────────────────

FACTOR_CATEGORIES: dict[str, list[str]] = {
    "动量": ["momentum_5", "momentum_10", "momentum_20", "momentum_60"],
    "RSI": ["rsi_7", "rsi_14"],
    "MACD": ["macd", "macd_5_35_5"],
    "量价": ["vol_ratio_5", "vol_ratio_20", "vol_chg_5"],
    "布林": ["boll", "boll_width"],
    "ATR": ["atr_14", "atr_ratio_14"],
    "均线": ["ma_cross_5_20", "ma_cross_10_60", "ma_dev_20", "ma_dev_60"],
    "波动率": ["volatility_20", "volatility_60", "down_vol_20"],
    "换手率": ["turnover_5", "turnover_chg_5"],
    "振幅": ["amplitude_5", "amplitude_20"],
    "基本面": ["roe", "pe", "pb", "ep"],
    "情绪": ["news_sent_5", "news_sent_20", "news_conf_5", "sent_delta_5"],
}


def get_factor(name: str, **overrides) -> BaseFactor:
    """按名称获取因子实例。

    参数:
        name: 因子名称（如 'momentum_20'）
        **overrides: 覆盖默认参数

    返回:
        BaseFactor 实例
    """
    if name not in _BUILTIN_FACTORIES:
        raise KeyError(f"未知因子: '{name}'。可用: {list(_BUILTIN_FACTORIES)}")
    factor = _BUILTIN_FACTORIES[name]()
    if overrides:
        for k, v in overrides.items():
            if hasattr(factor, k):
                setattr(factor, k, v)
        # 更新 factor.name
        if hasattr(factor, "name"):
            factor.name = name
    return factor


def list_factors(category: str | None = None) -> list[str]:
    """列出所有可用因子名称。"""
    if category and category in FACTOR_CATEGORIES:
        return FACTOR_CATEGORIES[category]
    return list(_BUILTIN_FACTORIES)


def list_categories() -> list[str]:
    """列出所有因子分类。"""
    return list(FACTOR_CATEGORIES)
