from __future__ import annotations

import pandas as pd

from .constants import TREND_BEAR, TREND_BULL, TREND_NEUTRAL
from .models import TrendEvent


def classify_bars(
    df: pd.DataFrame,
    use_body_range: bool,
    volume_filter_enabled: bool,
    volume_sma_window: int,
    volume_multiplier: float,
) -> pd.DataFrame:
    result = df.copy()
    result["classification"] = "unclassified"

    if volume_filter_enabled:
        vol_sma = result["Volume"].rolling(volume_sma_window, min_periods=1).mean()
        result["volume_ok"] = result["Volume"] >= (vol_sma * volume_multiplier)
    else:
        result["volume_ok"] = True

    for i in range(1, len(result)):
        prev = result.iloc[i - 1]
        cur = result.iloc[i]

        prev_high = max(prev["Open"], prev["Close"]) if use_body_range else prev["High"]
        prev_low = min(prev["Open"], prev["Close"]) if use_body_range else prev["Low"]

        if not bool(cur["volume_ok"]):
            result.iloc[i, result.columns.get_loc("classification")] = "fake"
        elif cur["Close"] > prev_high:
            result.iloc[i, result.columns.get_loc("classification")] = "real_bull"
        elif cur["Close"] < prev_low:
            result.iloc[i, result.columns.get_loc("classification")] = "real_bear"
        else:
            result.iloc[i, result.columns.get_loc("classification")] = "fake"

    result.iloc[0, result.columns.get_loc("classification")] = "unclassified"
    return result


def detect_trends(classified_df: pd.DataFrame) -> tuple[pd.DataFrame, list[TrendEvent]]:
    out = classified_df.copy()
    out["trend_state"] = TREND_NEUTRAL

    trend_state = TREND_NEUTRAL
    bull_run = 0
    bear_run = 0
    events: list[TrendEvent] = []

    for idx, row in out.iterrows():
        classification = row["classification"]

        if classification == "real_bull":
            bull_run += 1
            bear_run = 0

            if trend_state == TREND_NEUTRAL and bull_run >= 2:
                trend_state = TREND_BULL
                events.append(TrendEvent(idx, "Bullish trend started", trend_state))
            elif trend_state == TREND_BEAR and bull_run >= 2:
                trend_state = TREND_BULL
                events.append(TrendEvent(idx, "Bullish reversal confirmed (2 real bullish bars)", trend_state))

        elif classification == "real_bear":
            bear_run += 1
            bull_run = 0

            if trend_state == TREND_NEUTRAL and bear_run >= 2:
                trend_state = TREND_BEAR
                events.append(TrendEvent(idx, "Bearish trend started", trend_state))
            elif trend_state == TREND_BULL and bear_run >= 2:
                trend_state = TREND_BEAR
                events.append(TrendEvent(idx, "Bearish reversal confirmed (2 real bearish bars)", trend_state))

        out.at[idx, "trend_state"] = trend_state

    return out, events
