"""持有周期定义：把"周/双周/月/季/半年/年"或自定义交易日数，映射成
调仓间隔、动量/趋势回看窗口、反转权重。

设计原则：周期越短，越依赖短周期动量与反转；周期越长，越依赖中期动量与趋势，
并且因子回看窗口应大致等于 1~2 个持有周期，避免"用周线数据做季度决策"。
"""
from __future__ import annotations

# 周期名 -> 交易日数
PERIOD_DAYS = {
    "周": 5,
    "双周": 10,
    "月": 20,
    "季": 60,
    "半年": 120,
    "年": 250,
}

# 交易日数 -> 因子配置（momentum/trend 回看窗口、反转权重、对应 strategy_generator 的 horizon 名）
PERIOD_PROFILE = {
    5:   dict(horizon="短线", momentum=20,  trend=20,  reversal=0.20, label="周"),
    10:  dict(horizon="波段", momentum=60,  trend=60,  reversal=0.10, label="双周"),
    20:  dict(horizon="中线", momentum=120, trend=120, reversal=0.00, label="月"),
    60:  dict(horizon="长线", momentum=180, trend=200, reversal=0.00, label="季"),
    120: dict(horizon="半年", momentum=250, trend=250, reversal=0.00, label="半年"),
    250: dict(horizon="半年", momentum=250, trend=250, reversal=0.00, label="年"),
}


def resolve_period(period: str = None, days: int = None) -> dict:
    """解析周期参数，返回 {days, momentum, trend, reversal, horizon, label}。

    Args:
        period: 周/双周/月/季/半年/年
        days: 自定义交易日数（优先于 period）
    """
    if days is not None:
        days = int(days)
        if days < 3 or days > 250:
            raise ValueError("自定义周期需在 3~250 个交易日之间")
        profile = PERIOD_PROFILE.get(days)
        if profile:
            return dict(days=days, label=profile["label"], **{k: profile[k] for k in ("horizon", "momentum", "trend", "reversal")})
        # 任意天数：按交易日数自适应（回看窗口 ≈ 2~4 个周期，限制在 20~250）
        mom = int(max(20, min(250, round(days * 3))))
        trend = int(max(20, min(250, round(days * 6))))
        # 对应到最接近的 horizon
        nearest = min(PERIOD_PROFILE, key=lambda k: abs(k - days))
        return dict(days=days, label=f"自定义{days}日", horizon=PERIOD_PROFILE[nearest]["horizon"],
                    momentum=mom, trend=trend, reversal=0.0)

    if not period:
        period = "月"
    if period not in PERIOD_DAYS:
        raise ValueError(f"周期必须为 {list(PERIOD_DAYS)} 之一，或用 --days 指定交易日数")
    d = PERIOD_DAYS[period]
    profile = PERIOD_PROFILE[d]
    return dict(days=d, label=period, **{k: profile[k] for k in ("horizon", "momentum", "trend", "reversal")})
