#src/strategies/roc_momentum.py
"""
Estrategia de momentum basada en Rate of Change.
"""
from __future__ import annotations

import pandas as pd

from ..core.strategy import Strategy, Signal, calculate_roc


class ROCMomentum(Strategy):
    """
    Momentum puro basado en ROC.

    Señales:
    - BUY: ROC cruza por encima del umbral positivo
    - SELL: ROC cruza por debajo del umbral negativo
    """

    strategy_id = "roc_momentum"
    strategy_family = "momentum"
    display_name = "ROC Momentum"
    description = "Momentum basado en Rate of Change."

    def __init__(
        self,
        roc_window: int = 10,
        roc_threshold: float = 0.02,
        exit_threshold: float = 0.0,
    ):
        params = {
            "roc_window": roc_window,
            "roc_threshold": roc_threshold,
            "exit_threshold": exit_threshold,
        }
        super().__init__(name="ROC Momentum", params=params)

        self.roc_window = int(roc_window)
        self.roc_threshold = float(roc_threshold)
        self.exit_threshold = float(exit_threshold)

    @classmethod
    def default_parameters(cls) -> dict:
        return {
            "roc_window": 10,
            "roc_threshold": 0.02,
            "exit_threshold": 0.0,
        }

    @classmethod
    def strategy_metadata(cls) -> dict:
        return {
            "strategy_id": cls.strategy_id,
            "name": cls.display_name,
            "family": cls.strategy_family,
            "direction": "long_short",
            "description": cls.description,
        }

    @classmethod
    def strategy_definition(cls) -> dict:
        return {
            "meta": cls.strategy_metadata(),
            "defaults": cls.default_parameters(),
            "parameters_schema": cls.parameters_schema(),
        }

    @classmethod
    def parameters_schema(cls) -> dict:
        return {
            "roc_window": {
                "type": "int",
                "min": 1,
                "max": 300,
                "default": 10,
            },
            "roc_threshold": {
                "type": "float",
                "min": 0.0,
                "max": 1.0,
                "default": 0.02,
            },
            "exit_threshold": {
                "type": "float",
                "min": -1.0,
                "max": 1.0,
                "default": 0.0,
            },
        }

    def init_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
        data["roc"] = calculate_roc(data["close"], self.roc_window)

        data["roc_cross_up"] = (
            (data["roc"] > self.roc_threshold) &
            (data["roc"].shift(1) <= self.roc_threshold)
        )
        data["roc_cross_down"] = (
            (data["roc"] < -self.roc_threshold) &
            (data["roc"].shift(1) >= -self.roc_threshold)
        )

        data["roc_exit_long"] = (
            (data["roc"] < self.exit_threshold) &
            (data["roc"].shift(1) >= self.exit_threshold)
        )
        data["roc_exit_short"] = (
            (data["roc"] > -self.exit_threshold) &
            (data["roc"].shift(1) <= -self.exit_threshold)
        )

        return data

    def generate_signal(self, idx: int) -> Signal:
        if self.data is None:
            raise ValueError("Data no establecida")

        if idx < 1:
            return Signal.HOLD

        row = self.data.iloc[idx]
        if pd.isna(row["roc"]):
            return Signal.HOLD

        if bool(row["roc_cross_up"]) and self.current_position <= 0:
            return Signal.BUY

        if bool(row["roc_cross_down"]) and self.current_position >= 0:
            return Signal.SELL

        if self.current_position > 0 and bool(row["roc_exit_long"]):
            return Signal.SELL

        if self.current_position < 0 and bool(row["roc_exit_short"]):
            return Signal.BUY

        return Signal.HOLD
