import pandas as pd
import pandas_ta as ta
import logging
from typing import Dict
from app.strategies.base_strategy import BaseStrategy, StrategyResult

logger = logging.getLogger(__name__)

DEFAULT_PARAMS = {
    "rsi_period": 14,
    "oversold": 30,
    "overbought": 70,
    "timeframes": ["15m", "1h"],
}


class RSIStrategy(BaseStrategy):
    """
    RSI-based strategy with multi-timeframe confirmation.

    - BUY  when RSI < oversold (30), confidence scales with distance below 30.
    - SELL when RSI > overbought (70), confidence scales with distance above 70.
    - Both primary (15m) and confirmation (1h) timeframes must agree for a signal.
    """

    def __init__(self, params: dict = None):
        merged = {**DEFAULT_PARAMS, **(params or {})}
        super().__init__(name="RSI", params=merged)

    def _compute_rsi(self, df: pd.DataFrame) -> float:
        """Return the latest RSI value for the given DataFrame."""
        period = self.params["rsi_period"]
        rsi_series = ta.rsi(df["close"], length=period)
        if rsi_series is None or rsi_series.dropna().empty:
            return 50.0  # neutral fallback
        return float(rsi_series.dropna().iloc[-1])

    def _rsi_signal(self, rsi_val: float) -> tuple[str, float]:
        """Map an RSI value to (signal, confidence)."""
        oversold = self.params["oversold"]
        overbought = self.params["overbought"]

        if rsi_val < oversold:
            # Max confidence when RSI approaches 0
            confidence = min(100.0, ((oversold - rsi_val) / oversold) * 100)
            return "BUY", confidence
        elif rsi_val > overbought:
            # Max confidence when RSI approaches 100
            confidence = min(100.0, ((rsi_val - overbought) / (100 - overbought)) * 100)
            return "SELL", confidence
        return "HOLD", 0.0

    def analyze(self, data: Dict[str, pd.DataFrame]) -> StrategyResult:
        timeframes = self.params["timeframes"]
        primary_tf = timeframes[0]   # e.g. "15m"
        confirm_tf = timeframes[1] if len(timeframes) > 1 else None  # e.g. "1h"

        if primary_tf not in data:
            logger.warning(f"RSIStrategy: primary timeframe {primary_tf} not in data")
            return StrategyResult(signal="HOLD", confidence=0.0)

        primary_rsi = self._compute_rsi(data[primary_tf])
        primary_signal, primary_conf = self._rsi_signal(primary_rsi)

        confirm_rsi = None
        confirm_signal = "HOLD"
        if confirm_tf and confirm_tf in data:
            confirm_rsi = self._compute_rsi(data[confirm_tf])
            confirm_signal, _ = self._rsi_signal(confirm_rsi)

        # Both timeframes must agree (or confirmation timeframe unavailable)
        if confirm_tf and confirm_signal != primary_signal and confirm_signal != "HOLD":
            # Conflicting signals -> downgrade to HOLD
            final_signal = "HOLD"
            final_confidence = 0.0
        else:
            final_signal = primary_signal
            # Slightly boost confidence if confirmation agrees
            boost = 10.0 if confirm_signal == primary_signal else 0.0
            final_confidence = min(100.0, primary_conf + boost)

        return StrategyResult(
            signal=final_signal,
            confidence=final_confidence,
            metadata={
                "primary_rsi": round(primary_rsi, 2),
                "primary_timeframe": primary_tf,
                "confirm_rsi": round(confirm_rsi, 2) if confirm_rsi is not None else None,
                "confirm_timeframe": confirm_tf,
            },
        )
