import logging
from typing import List, Dict, Any, Optional
from app.strategies.base_strategy import BaseStrategy, StrategyResult
from app.core.support_resistance import detect_levels
from app.core.market_condition import detect_market_condition

logger = logging.getLogger(__name__)

# Minimum weighted confidence to generate a signal
CONFIDENCE_THRESHOLD = 55.0


class DecisionEngine:
    """
    Aggregates signals from multiple strategies using weighted scoring.
    Produces a final BUY/SELL/HOLD decision with metadata.
    """

    def __init__(self, strategies: List[BaseStrategy]):
        self.strategies = strategies

    def analyze(
        self,
        pair: str,
        market_data: Dict[str, Any],
        strategy_weights: Optional[Dict[str, float]] = None,
        current_price: Optional[float] = None,
    ) -> Dict[str, Any]:
        """
        Run all strategies and aggregate results.

        Args:
            pair:             Trading pair symbol, e.g. "BTC/USDT"
            market_data:      Multi-timeframe OHLCV dict {"15m": df, "1h": df}
            strategy_weights: Optional dict mapping strategy name to weight (0-1)
            current_price:    Latest price (used as entry estimate)

        Returns:
            dict with final signal, confidence, entry, SL, TPs, breakdown, S/R levels.
        """
        if strategy_weights is None:
            strategy_weights = {}

        results: List[Dict[str, Any]] = []
        for strategy in self.strategies:
            try:
                result: StrategyResult = strategy.analyze(market_data)
                weight = strategy_weights.get(strategy.get_name(), 1.0)
                results.append({
                    "strategy": strategy.get_name(),
                    "signal": result.signal,
                    "confidence": result.confidence,
                    "weight": weight,
                    "metadata": result.metadata,
                })
            except Exception as e:
                logger.error(f"Strategy {strategy.get_name()} failed: {e}")

        final_signal, confidence = self._aggregate(results)

        # Market condition and support/resistance from 1h data
        primary_df = market_data.get("1h")
        if primary_df is None and market_data:
            primary_df = market_data.get(list(market_data.keys())[0])
        sr_levels = detect_levels(primary_df) if primary_df is not None else {}
        market_condition = detect_market_condition(primary_df) if primary_df is not None else "UNKNOWN"

        entry = current_price or (
            float(primary_df["close"].iloc[-1]) if primary_df is not None else 0.0
        )

        return {
            "pair": pair,
            "signal": final_signal,
            "confidence": round(confidence, 2),
            "entry": entry,
            "market_condition": market_condition,
            "strategies_breakdown": results,
            "support_resistance": sr_levels,
        }

    def _aggregate(
        self, results: List[Dict[str, Any]]
    ) -> tuple[str, float]:
        """
        Weighted voting:
        - Sum weighted confidence for BUY signals.
        - Sum weighted confidence for SELL signals.
        - Winning direction must exceed CONFIDENCE_THRESHOLD.
        """
        if not results:
            return "HOLD", 0.0

        buy_score = 0.0
        sell_score = 0.0
        total_weight = 0.0

        for r in results:
            w = r["weight"]
            total_weight += w
            if r["signal"] == "BUY":
                buy_score += r["confidence"] * w
            elif r["signal"] == "SELL":
                sell_score += r["confidence"] * w

        if total_weight == 0:
            return "HOLD", 0.0

        buy_conf = buy_score / total_weight
        sell_conf = sell_score / total_weight

        if buy_conf >= sell_conf and buy_conf >= CONFIDENCE_THRESHOLD:
            return "BUY", buy_conf
        elif sell_conf > buy_conf and sell_conf >= CONFIDENCE_THRESHOLD:
            return "SELL", sell_conf

        return "HOLD", max(buy_conf, sell_conf)
