"""Ichimoku Cloud algorithm."""
from __future__ import annotations
import numpy as np
from app.engine.base import BaseAlgorithm
from app.engine.context import AlgorithmContext


class IchimokuAlgorithm(BaseAlgorithm):
    algorithm_id = 'technical.ichimoku'
    version = '1.0.0'
    category = 'technical'
    display_name = 'Ichimoku Cloud'
    dependencies = []

    def __init__(self, tenkan: int = 9, kijun: int = 26, senkou_b: int = 52):
        self.tenkan_period = tenkan
        self.kijun_period = kijun
        self.senkou_b_period = senkou_b

    def _midpoint(self, highs, lows, period, idx):
        """Highest high + lowest low over period, divided by 2."""
        start = max(0, idx - period + 1)
        window_h = highs[start:idx + 1]
        window_l = lows[start:idx + 1]
        if len(window_h) < period:
            return None
        return (float(np.max(window_h)) + float(np.min(window_l))) / 2

    def compute(self, ctx: AlgorithmContext) -> AlgorithmContext:
        df = ctx.ohlcv
        if df is None or len(df) < self.senkou_b_period + self.kijun_period:
            return ctx

        highs = df['high'].values.astype(float)
        lows = df['low'].values.astype(float)
        closes = df['close'].values.astype(float)
        n = len(closes)

        tenkan = [None] * n
        kijun = [None] * n
        senkou_a = [None] * n
        senkou_b = [None] * n

        for i in range(n):
            tenkan[i] = self._midpoint(highs, lows, self.tenkan_period, i)
            kijun[i] = self._midpoint(highs, lows, self.kijun_period, i)

            if tenkan[i] is not None and kijun[i] is not None:
                senkou_a[i] = (tenkan[i] + kijun[i]) / 2

            senkou_b[i] = self._midpoint(highs, lows, self.senkou_b_period, i)

        # Chikou Span = close shifted 26 periods back (plot only)
        chikou = [None] * n
        for i in range(self.kijun_period, n):
            chikou[i - self.kijun_period] = closes[i]

        ctx.indicators['ichimoku_tenkan'] = tenkan
        ctx.indicators['ichimoku_kijun'] = kijun
        ctx.indicators['ichimoku_senkou_a'] = senkou_a
        ctx.indicators['ichimoku_senkou_b'] = senkou_b
        ctx.indicators['ichimoku_chikou'] = chikou

        # Latest values for signal
        ctx.indicators['ichimoku_tenkan_latest'] = tenkan[-1]
        ctx.indicators['ichimoku_kijun_latest'] = kijun[-1]
        ctx.indicators['ichimoku_senkou_a_latest'] = senkou_a[-1]
        ctx.indicators['ichimoku_senkou_b_latest'] = senkou_b[-1]

        # Cloud color
        sa, sb = senkou_a[-1], senkou_b[-1]
        if sa is not None and sb is not None:
            ctx.indicators['ichimoku_cloud'] = 'bullish' if sa > sb else 'bearish'
        return ctx

    def get_signal_contribution(self, ctx: AlgorithmContext) -> dict | None:
        tenkan = ctx.indicators.get('ichimoku_tenkan_latest')
        kijun = ctx.indicators.get('ichimoku_kijun_latest')
        cloud = ctx.indicators.get('ichimoku_cloud')
        price = ctx.current_price

        if tenkan is None or kijun is None or not price:
            return None

        sa = ctx.indicators.get('ichimoku_senkou_a_latest', 0)
        sb = ctx.indicators.get('ichimoku_senkou_b_latest', 0)
        cloud_top = max(sa or 0, sb or 0)
        cloud_bottom = min(sa or 0, sb or 0)

        # Strong buy: price above cloud + tenkan > kijun
        if price > cloud_top and tenkan > kijun:
            return {'signal': 'BUY', 'weight': 0.12,
                    'reason': f'Price above Ichimoku cloud ({cloud}), TK cross bullish'}
        # Strong sell: price below cloud + tenkan < kijun
        elif price < cloud_bottom and tenkan < kijun:
            return {'signal': 'SELL', 'weight': 0.12,
                    'reason': f'Price below Ichimoku cloud ({cloud}), TK cross bearish'}
        # Inside cloud = consolidation
        elif cloud_bottom <= price <= cloud_top:
            return {'signal': 'HOLD', 'weight': 0.05,
                    'reason': 'Price inside Ichimoku cloud — consolidation'}

        return {'signal': 'HOLD', 'weight': 0.05, 'reason': 'Ichimoku mixed signals'}
