"""SignalRouter — routes PULSE signals to configured exchange adapters."""

import logging
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)


class SignalRouter:
    """Route incoming TradingView signals to one or more exchange adapters.

    Supports any PULSE-compatible adapter: pulse-binance, pulse-bybit,
    pulse-kraken, pulse-okx, or pulse-freqtrade.

    Example:
        >>> from pulse_binance import BinanceAdapter
        >>> router = SignalRouter()
        >>> router.add_adapter(BinanceAdapter(api_key="...", api_secret="..."))
        >>> router.route({"pair": "BTC/USDT", "direction": "long", "price": 83000})
    """

    def __init__(self):
        self._adapters: List = []
        self._filters: List = []

    def add_adapter(self, adapter, name: Optional[str] = None) -> "SignalRouter":
        """Add an exchange adapter to route signals to.

        Args:
            adapter: Any PULSE-compatible adapter (BinanceAdapter, BybitAdapter, etc.)
            name: Optional label for logging

        Returns:
            Self for chaining.
        """
        label = name or getattr(adapter, "__class__", type(adapter)).__name__
        self._adapters.append((label, adapter))
        logger.info(f"Added adapter: {label}")
        return self

    def add_filter(self, fn) -> "SignalRouter":
        """Add a filter function that can block signals.

        The filter receives the parsed parameters dict and returns True to
        allow the signal, False to drop it.

        Example:
            >>> router.add_filter(lambda p: p["confidence"] >= 0.8)
            >>> router.add_filter(lambda p: p["pair"] in ["BTC/USDT", "ETH/USDT"])

        Args:
            fn: Callable that takes params dict and returns bool

        Returns:
            Self for chaining.
        """
        self._filters.append(fn)
        return self

    def route(self, params: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Route a parsed signal to all configured adapters.

        Args:
            params: Parsed alert parameters from AlertConverter

        Returns:
            List of results from each adapter (one per adapter).
        """
        # Apply filters
        for f in self._filters:
            if not f(params):
                logger.info(
                    f"Signal filtered out: {params.get('pair')} {params.get('direction')} "
                    f"(confidence={params.get('confidence')})"
                )
                return []

        if not self._adapters:
            logger.warning("No adapters configured — signal dropped")
            return []

        results = []
        for label, adapter in self._adapters:
            try:
                result = self._send_to_adapter(adapter, params, label)
                results.append({"adapter": label, "status": "ok", "result": result})
                logger.info(
                    f"Signal sent to {label}: {params.get('pair')} {params.get('direction')}"
                )
            except Exception as e:
                logger.error(f"Error sending to {label}: {e}")
                results.append({"adapter": label, "status": "error", "error": str(e)})

        return results

    def _send_to_adapter(self, adapter, params: Dict[str, Any], label: str):
        """Send signal to a specific adapter using PULSE message format."""
        # Import here to avoid circular imports
        try:
            from pulse.message import PulseMessage
        except ImportError:
            raise ImportError(
                "pulse-protocol not installed. Run: pip install pulse-protocol"
            )

        direction = params.get("direction", "neutral")

        # Build PULSE message
        msg_params = {
            "pair": params.get("pair", ""),
            "direction": direction,
            "confidence": params.get("confidence", 1.0),
            "source": params.get("source", "tradingview"),
        }
        if "price" in params:
            msg_params["price"] = params["price"]
        if "interval" in params:
            msg_params["interval"] = params["interval"]

        # For exchange adapters: use ACT.TRANSACT.REQUEST for actual trades
        # For signal-only flow: use ACT.RECOMMEND.ACTION
        adapter_class = type(adapter).__name__

        if direction == "neutral":
            # Close/exit signal — use ACT.CANCEL if supported
            msg = PulseMessage(
                action="ACT.RECOMMEND.ACTION",
                parameters=msg_params,
                validate=False,
            )
        elif adapter_class in ("FreqtradeAdapter",):
            # Freqtrade: inject as signal recommendation, not direct trade
            msg = PulseMessage(
                action="ACT.RECOMMEND.ACTION",
                parameters=msg_params,
                validate=False,
            )
        else:
            # Direct exchange adapter: place trade
            trade_params = {
                "pair": params.get("pair", ""),
                "symbol": params.get("symbol", ""),
                "side": "BUY" if direction == "long" else "SELL",
                "type": "MARKET",
            }
            if "price" in params:
                trade_params["price"] = params["price"]

            msg = PulseMessage(
                action="ACT.TRANSACT.REQUEST",
                parameters=trade_params,
                validate=False,
            )

        # Connect if needed
        if hasattr(adapter, "connect") and not getattr(adapter, "_connected", False):
            adapter.connect()

        response = adapter.send(msg)
        return response.content if hasattr(response, "content") else response
