#!/usr/bin/env python3
"""
strategy_interface.py — 策略抽象接口
所有可训练/可进化的策略必须实现此接口。

兼容 signal_generators.BaseSignalGenerator (analyze + get_params_schema)
新增 param_grid / default_params 供 offline_train 和 evolution_pipeline 使用。
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Optional


@dataclass
class BacktestScore:
    total_trades: int = 0
    wins: int = 0
    losses: int = 0
    total_pnl: float = 0.0
    win_rate: float = 0.0
    score: float = -9999.0
    by_regime: dict = field(default_factory=dict)
    by_side: dict = field(default_factory=dict)
    trades_list: list = field(default_factory=list)


class SignalStrategy(ABC):
    """
    策略抽象基类。

    实现该接口的策略可以在 offline_train 中进行网格搜索和回测，
    也可以在 evolution_pipeline 中通过 LLM 生成和自动进化。

    与 signal_generators.BaseSignalGenerator 兼容：
    - analyze(bars, params) 方法签名一致
    - 额外需要 param_grid() 和 default_params()
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """策略唯一标识符，用于注册和追踪"""

    @abstractmethod
    def analyze(self, bars: list[dict], params: dict) -> dict:
        """
        分析K线数据，返回信号。

        Args:
            bars: K线列表 [{"time", "open", "high", "low", "close", "tick_volume"}, ...]
            params: 策略参数字典

        Returns:
            dict with payload.action ∈ {"OPEN", "HOLD"}, payload.side ∈ {"BUY", "SELL"},
                 payload.entry, payload.sl, payload.tp, payload.confidence, payload.regime
        """

    @abstractmethod
    def param_grid(self) -> dict[str, list]:
        """
        返回可搜索的参数空间。

        Returns:
            {"param_name": [value1, value2, ...], ...}
            用于 itertools.product 生成所有组合。
        """

    @abstractmethod
    def default_params(self) -> dict:
        """返回默认参数"""

    def validate_params(self, params: dict) -> dict:
        """验证并补全参数（默认实现：用 default_params 补缺）"""
        complete = dict(self.default_params())
        complete.update(params)
        return complete

    def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name!r})"


def create_strategy(strategy_type: str, **kwargs) -> SignalStrategy:
    """
    策略工厂：根据类型名创建策略实例。

    strategy_type:
      "ema_macd" / "ema_rsi_bb"  → EmaRsiBbStrategy
      "grid"                     → GridStrategyAdapter
      "composite"                → CompositeStrategyAdapter
    """
    strategy_type = strategy_type.lower().strip()

    if strategy_type in ("ema_macd", "ema_rsi_bb", "ema", "default"):
        from contracts.strategy_adapters import EmaRsiBbAdapter
        return EmaRsiBbAdapter(**kwargs)

    if strategy_type in ("grid", "grid_strategy"):
        from contracts.strategy_adapters import GridStrategyAdapter
        return GridStrategyAdapter(**kwargs)

    if strategy_type in ("composite", "multi", "hybrid"):
        from contracts.strategy_adapters import CompositeStrategyAdapter
        return CompositeStrategyAdapter(**kwargs)

    raise ValueError(
        f"Unknown strategy type: {strategy_type}. "
        f"Available: ema_macd, grid, composite"
    )
