"""
V15 — Strategy: Momentum Taker con confirmación mínima (CONFIRM_TICKS=1).

Arquitectura de V12 con CONFIRM_TICKS=1 (validado: 3 ticks perdía 60%
de ventanas rentables). Entra al primer tick que cruza threshold,
similar a V11 pero con la estructura modular de V12.
"""
from dataclasses import dataclass
from typing import Optional

from .config import (
    Config,
    MOMENTUM_THRESHOLD, CONFIRM_TICKS,
    MAX_ENTRY_PRICE, MIN_ENTRY_PRICE,
    ENTRY_SIZE_USD, MIN_SHARES,
    TAKER_FEE_RATE, PAPER_SLIPPAGE,
    TICK_SIZE, snap_price,
)


@dataclass
class Signal:
    """Señal de momentum detectada."""
    side: str           # "YES" o "NO"
    token_id: str       # Token a comprar
    price: float        # Precio estimado de entrada
    size: float         # Shares a comprar
    size_usd: float     # USD
    move_pct: float     # Movimiento % que disparó la señal
    confirm_count: int = 0  # V12: ticks de confirmación acumulados
    reason: str = ""    # Por qué se generó


class MomentumStrategy:
    def __init__(self, cfg: Config):
        self.cfg = cfg
        # V12: estado de confirmación
        self._confirm_count = 0     # ticks consecutivos con señal válida
        self._confirm_side = ""     # dirección actual ("YES" o "NO")

    def reset(self):
        """Reset confirmation state (llamar al inicio de cada ventana)."""
        self._confirm_count = 0
        self._confirm_side = ""

    @property
    def confirm_count(self) -> int:
        """Ticks de confirmación acumulados (para dashboard)."""
        return self._confirm_count

    @property
    def confirm_side(self) -> str:
        """Dirección actual de confirmación (para dashboard)."""
        return self._confirm_side

    def check_signal(self, price: float, strike: float, t_left: int,
                     token_yes: str, token_no: str,
                     best_ask_yes: float, best_ask_no: float,
                     already_entered: bool) -> Optional[Signal]:
        """Evalúa si hay señal de momentum CON CONFIRMACIÓN.

        Returns Signal si hay que entrar, None si no.
        La señal solo se genera tras confirm_ticks ticks consecutivos
        con |move| > threshold en la misma dirección.
        """
        if already_entered:
            return None

        if strike <= 0 or price <= 0:
            return None

        # Timing check (from config, depends on window duration)
        if t_left > self.cfg.signal_start_tleft:
            return None
        if t_left < self.cfg.signal_stop_tleft:
            return None

        # Calcular movimiento
        move = (price - strike) / strike
        abs_move = abs(move)

        # --- V12: Confirmación de momentum ---
        if abs_move < self.cfg.momentum_threshold:
            # Movimiento insuficiente → reset contador
            self._confirm_count = 0
            self._confirm_side = ""
            return None

        # Determinar dirección candidata
        candidate_side = "YES" if move > 0 else "NO"

        # Si la dirección cambió, reset
        if candidate_side != self._confirm_side:
            self._confirm_count = 1
            self._confirm_side = candidate_side
        else:
            self._confirm_count += 1

        # No confirmar aún → no generar señal
        if self._confirm_count < self.cfg.confirm_ticks:
            return None

        # --- Confirmación completada: evaluar filtros de entrada ---

        if candidate_side == "YES":
            side = "YES"
            token_id = token_yes
            entry_price = best_ask_yes
        else:
            side = "NO"
            token_id = token_no
            entry_price = best_ask_no

        # Sin precio real del CLOB, no entrar — no inventar precios
        if entry_price <= 0:
            self._confirm_count = 0
            self._confirm_side = ""
            return None

        entry_price = snap_price(entry_price)

        # Filtro de precio (per-asset: ETH/SOL max 0.55, BTC max 0.65)
        if entry_price > self.cfg.max_entry_price:
            self._confirm_count = 0
            self._confirm_side = ""
            return None
        if entry_price < MIN_ENTRY_PRICE:
            self._confirm_count = 0
            self._confirm_side = ""
            return None

        # Confirmación CLOB: para assets donde Binance/Polymarket divergen
        # (ETH, SOL, etc), solo entrar si el CLOB ya refleja nuestra dirección.
        # Precio bajo = mercado no ve el move → señal poco fiable.
        if entry_price < self.cfg.min_ask_confirm:
            self._confirm_count = 0
            self._confirm_side = ""
            return None

        # Calcular tamaño
        n_shares = max(round(self.cfg.entry_size_usd / entry_price, 2), MIN_SHARES)
        cost_usd = round(n_shares * entry_price, 2)

        return Signal(
            side=side,
            token_id=token_id,
            price=entry_price,
            size=n_shares,
            size_usd=cost_usd,
            move_pct=round(move * 100, 4),
            confirm_count=self._confirm_count,
            reason=(f"momentum {move:+.4%} > threshold "
                    f"{self.cfg.momentum_threshold:.4%} "
                    f"(confirmed {self._confirm_count} ticks)"),
        )
