# src/strategies/trend_filtered.py

import pandas as pd
import numpy as np

from src.strategies.base import Strategy
from src.core.strategy import Signal


class TrendFilteredMACrossover(Strategy):
    """
    Estrategia de cruce de medias con filtro de tendencia.

    Señales:
    - BUY:
        * Cruce alcista de medias
        * Precio por encima de MA lenta
        * ADX >= threshold
    - SELL:
        * Cruce bajista de medias
    - HOLD:
        * En cualquier otro caso

    Objetivo:
    - Evitar whipsaws en mercado lateral
    - Operar solo cuando hay estructura de tendencia

    Parámetros por defecto:
        fast_period=20
        slow_period=50
        ma_type='ema'
        adx_period=14
        adx_threshold=20
    """

    def __init__(
        self,
        fast_period: int = 20,
        slow_period: int = 50,
        ma_type: str = "ema",
        adx_period: int = 14,
        adx_threshold: float = 20.0,
    ):
        params = {
            "fast_period": fast_period,
            "slow_period": slow_period,
            "ma_type": ma_type,
            "adx_period": adx_period,
            "adx_threshold": adx_threshold,
        }

        super().__init__(name="TrendFilteredMACrossover", params=params)

        self.fast_period = fast_period
        self.slow_period = slow_period
        self.ma_type = ma_type
        self.adx_period = adx_period
        self.adx_threshold = adx_threshold

    # --------------------------------------------------

    def init_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
        # Medias móviles
        if self.ma_type == "ema":
            data["ma_fast"] = data["close"].ewm(
                span=self.fast_period, adjust=False
            ).mean()
            data["ma_slow"] = data["close"].ewm(
                span=self.slow_period, adjust=False
            ).mean()
        else:
            data["ma_fast"] = data["close"].rolling(self.fast_period).mean()
            data["ma_slow"] = data["close"].rolling(self.slow_period).mean()

        return data

    # --------------------------------------------------

    def generate_signal(self, idx: int) -> Signal:
        if self.data is None or idx < 1:
            return Signal.HOLD

        required = {"ma_fast", "ma_slow", "adx", "close"}
        if not required.issubset(self.data.columns):
            return Signal.HOLD

        row = self.data.iloc[idx]
        prev = self.data.iloc[idx - 1]

        if pd.isna(row.adx):
            return Signal.HOLD

        cross_up = prev.ma_fast <= prev.ma_slow and row.ma_fast > row.ma_slow
        cross_down = prev.ma_fast >= prev.ma_slow and row.ma_fast < row.ma_slow

        trend_ok = row.close > row.ma_slow and row.adx >= self.adx_threshold

        if cross_up and trend_ok:
            return Signal.BUY

        if cross_down:
            return Signal.SELL

        return Signal.HOLD
