"""Strategy Selector - recommends best strategy per asset based on conditions.

Analyzes volatility, trend, and timeframe to recommend:
- Scalping: High volatility, short timeframes
- Swing: Medium volatility, medium timeframes
- Investment: Low volatility or strong trend, long timeframes
"""
from __future__ import annotations
from app.engine.base import BaseAlgorithm
from app.engine.context import AlgorithmContext


class StrategySelectorAlgorithm(BaseAlgorithm):
    algorithm_id = 'strategy.selector'
    version = '1.0.0'
    category = 'strategy'
    display_name = 'Strategy Selector'
    dependencies = ['strategy.scalping', 'strategy.swing', 'strategy.investment']

    # Volatility thresholds
    LOW_VOL = 1.5
    HIGH_VOL = 4.0

    def compute(self, ctx: AlgorithmContext) -> AlgorithmContext:
        atr_pct = ctx.indicators.get('atr_pct', 2.0)
        rsi = ctx.indicators.get('rsi_latest', 50)

        # Collect strategy scores
        strategies = {}

        scalp = ctx.strategy.get('scalping', {})
        swing = ctx.strategy.get('swing', {})
        invest = ctx.strategy.get('investment', {})

        # Scalping suitability — penalize in high volatility (whipsaws)
        scalp_score = 0
        if atr_pct and self.LOW_VOL < atr_pct <= self.HIGH_VOL:
            scalp_score += 2  # moderate vol: good for scalping
        elif atr_pct and atr_pct > self.HIGH_VOL:
            scalp_score -= 2  # high vol: too many whipsaws, penalize
        if ctx.timeframe in ('1h', '4h'):
            scalp_score += 2
        if scalp.get('applicable'):
            scalp_score += 1
        strategies['scalping'] = {
            'score': scalp_score,
            'signal': scalp.get('best_buy', {}).get('action', 'HOLD') if scalp.get('best_buy') else 'HOLD',
        }

        # Swing suitability
        swing_score = 0
        if atr_pct and self.LOW_VOL <= atr_pct <= self.HIGH_VOL:
            swing_score += 2
        if ctx.timeframe in ('4h', '1D'):
            swing_score += 2
        if swing.get('applicable'):
            swing_score += abs(swing.get('score', 0))
        strategies['swing'] = {
            'score': swing_score,
            'signal': swing.get('signal', 'HOLD'),
        }

        # Investment suitability
        invest_score = 0
        if atr_pct and atr_pct < self.HIGH_VOL:
            invest_score += 1
        if ctx.timeframe in ('1D', '1W'):
            invest_score += 3
        if rsi and rsi < 35:
            invest_score += 2  # Oversold = good long-term entry
        if invest.get('score', 0) >= 2:
            invest_score += invest['score']
        strategies['investment'] = {
            'score': invest_score,
            'signal': invest.get('signal', 'HOLD'),
        }

        # Select best strategy
        best = max(strategies.items(), key=lambda x: x[1]['score'])
        recommended = best[0]

        # Safety rating based on volatility + RSI
        if atr_pct and atr_pct > 6:
            safety = 'DANGEROUS'
        elif atr_pct and atr_pct > self.HIGH_VOL:
            safety = 'RISKY'
        elif rsi and (rsi < 20 or rsi > 80):
            safety = 'MODERATE'
        else:
            safety = 'SAFE'

        # Capital preservation: don't scalp in dangerous/risky conditions
        if safety in ('DANGEROUS', 'RISKY') and recommended == 'scalping':
            recommended = 'swing'  # safer fallback

        ctx.strategy['selector'] = {
            'recommended': recommended,
            'safety_rating': safety,
            'strategies': strategies,
            'atr_pct': round(atr_pct, 2) if atr_pct else None,
        }
        return ctx

    def get_signal_contribution(self, ctx: AlgorithmContext) -> dict | None:
        sel = ctx.strategy.get('selector', {})
        if not sel:
            return None

        recommended = sel.get('recommended', 'investment')
        strats = sel.get('strategies', {})
        rec_data = strats.get(recommended, {})

        signal = rec_data.get('signal', 'HOLD')
        safety = sel.get('safety_rating', 'SAFE')

        return {
            'signal': signal,
            'weight': 0.10,
            'reason': f"Best strategy: {recommended} (safety={safety})",
        }
