#src/strategies/strategy_template.py
from __future__ import annotations

from typing import Any, Dict

import pandas as pd

from .base import BaseStrategy
from ..core.strategy import Strategy, Signal


class TemplateStrategy(Strategy):
    """
    Plantilla base para nuevas estrategias del strategy_repository.

    Objetivo:
    - Servir como archivo de referencia para copiar/pegar.
    - Mantener compatibilidad con el framework actual.
    - Estandarizar metadatos, defaults y parameters_schema.
    - No se debe registrar ni usar en producción tal cual.

    Contrato esperado por el framework actual:
    - strategy_id
    - parameters_schema()
    - init_indicators()
    - generate_signal()

    Contrato adicional recomendado para el repository:
    - default_parameters()
    - strategy_metadata()
    - strategy_definition()
    """

    strategy_id = "template_strategy"
    strategy_family = "template"
    display_name = "Template Strategy"
    description = "Plantilla de referencia para crear nuevas estrategias."

    def __init__(self, **params):
        """
        Aquí define los parámetros que realmente usará la estrategia.

        Recomendación:
        - usar params.get(...) con defaults explícitos
        - castear tipos si hace falta
        - no meter lógica pesada aquí
        """
        self.example_period = int(params.get("example_period", 20))
        self.example_threshold = float(params.get("example_threshold", 0.0))

    @classmethod
    def default_parameters(cls) -> Dict[str, Any]:
        """
        Parámetros por defecto para ejecución rápida y catálogo.
        """
        return {
            "example_period": 20,
            "example_threshold": 0.0,
        }

    @classmethod
    def parameters_schema(cls) -> Dict[str, Dict[str, Any]]:
        """
        Schema de parámetros para UI, validación y futura optimización.

        Formato compatible con el estilo actual de tus estrategias.
        """
        return {
            "example_period": {
                "type": "int",
                "min": 2,
                "max": 200,
                "default": 20,
                "step": 1,
                "description": "Periodo de ejemplo para indicador o ventana.",
            },
            "example_threshold": {
                "type": "float",
                "min": -10.0,
                "max": 10.0,
                "default": 0.0,
                "step": 0.1,
                "description": "Umbral de ejemplo para disparar señales.",
            },
        }

    @classmethod
    def strategy_metadata(cls) -> Dict[str, Any]:
        """
        Metadatos estándar para catálogo, reporting y clasificación por familia.
        """
        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[str, Any]:
        """
        Definición compacta y estandarizada de la estrategia.
        Útil para catálogo enriquecido y futuras capas del pipeline.
        """
        return {
            "meta": cls.strategy_metadata(),
            "defaults": cls.default_parameters(),
            "parameters_schema": cls.parameters_schema(),
        }

    def init_indicators(self, df: pd.DataFrame) -> pd.DataFrame:
        """
        Calcula y añade al DataFrame las columnas auxiliares necesarias.

        Convención recomendada:
        - no modificar el df original fuera de una copia
        - crear columnas con nombres claros
        - evitar side effects
        """
        out = df.copy()

        # Ejemplo simple:
        out["example_ma"] = out["close"].rolling(self.example_period).mean()

        return out

    def generate_signal(self, row: pd.Series) -> Signal:
        """
        Devuelve la señal de trading para una fila.

        Convención típica:
        -  1 => long
        - -1 => short
        -  0 => flat / no signal

        Sustituir esta lógica por la real de la estrategia.
        """
        example_ma = row.get("example_ma")

        if pd.isna(example_ma):
            return 0

        close = row.get("close")
        if close is None or pd.isna(close):
            return 0

        if close > (example_ma + self.example_threshold):
            return 1

        if close < (example_ma - self.example_threshold):
            return -1

        return 0