"""
参数搜索空间定义。
"""

from dataclasses import dataclass, field

import optuna


@dataclass
class SearchSpace:
    """参数搜索空间。"""

    params: list[dict] = field(default_factory=list)
    # 每个元素: {"name": str, "type": "int"|"float"|"categorical",
    #            "low": float, "high": float, "step": float, "choices": list}

    def suggest(self, trial: optuna.Trial) -> dict:
        """从 trial 中采样一组参数。"""
        result = {}
        for p in self.params:
            name = p["name"]
            kind = p["type"]
            if kind == "int":
                low = p.get("low", 0)
                high = p.get("high", 100)
                step = p.get("step", 1)
                result[name] = trial.suggest_int(name, int(low), int(high), step=int(step))
            elif kind == "float":
                low = p.get("low", 0.0)
                high = p.get("high", 1.0)
                result[name] = trial.suggest_float(name, float(low), float(high))
            elif kind == "categorical":
                choices = p.get("choices", [])
                result[name] = trial.suggest_categorical(name, choices)
        return result


# ── 预置搜索空间 ──────────────────────────────────────────

sma_cross_space = SearchSpace(params=[
    {"name": "fast", "type": "int", "low": 2, "high": 30, "step": 1},
    {"name": "slow", "type": "int", "low": 15, "high": 120, "step": 5},
])

rsi_revert_space = SearchSpace(params=[
    {"name": "oversold", "type": "int", "low": 10, "high": 45, "step": 1},
    {"name": "overbought", "type": "int", "low": 55, "high": 90, "step": 1},
])

momentum_breakout_space = SearchSpace(params=[
    {"name": "lookback", "type": "int", "low": 10, "high": 60, "step": 5},
    {"name": "exit_period", "type": "int", "low": 5, "high": 30, "step": 1},
])

factor_cross_space = SearchSpace(params=[
    {"name": "buy_threshold", "type": "float", "low": -10.0, "high": 10.0},
    {"name": "sell_threshold", "type": "float", "low": -10.0, "high": 10.0},
])

# 名称 → 空间映射
SPACES = {
    "sma_cross": sma_cross_space,
    "rsi_revert": rsi_revert_space,
    "momentum_breakout": momentum_breakout_space,
    "factor_cross": factor_cross_space,
}
