import numpy as np

def detect_momentum_divergence(bars, rsi_series, side="BUY", lookback=20, atr_v=None):
    """
    判断动量背离 (价格创新高/新低，但 RSI 不跟随)
    使用真实 ATR 作为距离阈值，而非固定百分比，以适应不同价格水平和波动率
    """
    if len(bars) < lookback or len(rsi_series) < lookback:
        return "MIDDLE"
        
    recent_bars = bars[-lookback:]
    recent_rsi = rsi_series[-lookback:]
    
    # 兜底 ATR，防止未传入
    current_atr = atr_v if atr_v and atr_v > 0 else (bars[-1]["high"] - bars[-1]["low"])
    
    if side == "BUY":
        recent_high = max(bar["high"] for bar in recent_bars)
        recent_rsi_high = max(recent_rsi)
        
        current_close = bars[-1]["close"]
        current_rsi = rsi_series[-1]
        
        # LATE: 价格接近或突破前高（允许 0.2 ATR 的误差），但 RSI 显著低于前高 RSI
        if current_close >= recent_high - 0.2 * current_atr and current_rsi < recent_rsi_high - 5:
            return "LATE_STAGE"
        # EARLY: 价格距离前高还很远（大于 1.0 ATR），但 RSI 已经突破或接近前高 RSI
        if current_close < recent_high - 1.0 * current_atr and current_rsi > recent_rsi_high + 5:
            return "EARLY_STAGE"
            
    else: # SELL
        recent_low = min(bar["low"] for bar in recent_bars)
        recent_rsi_low = min(recent_rsi)
        
        current_close = bars[-1]["close"]
        current_rsi = rsi_series[-1]
        
        # LATE: 价格接近或突破前低（允许 0.2 ATR 的误差），但 RSI 显著高于前低 RSI
        if current_close <= recent_low + 0.2 * current_atr and current_rsi > recent_rsi_low + 5:
            return "LATE_STAGE"
        # EARLY: 价格距离前低还很远（大于 1.0 ATR），但 RSI 已经跌破或接近前低 RSI
        if current_close > recent_low + 1.0 * current_atr and current_rsi < recent_rsi_low - 5:
            return "EARLY_STAGE"
            
    return "MIDDLE"

def adx_momentum(adx_series, window=10):
    """
    判断 ADX 变化率 (趋势是在加速还是衰竭)
    """
    if len(adx_series) < window + 1:
        return "STABLE"
        
    # Use simple difference over the window
    adx_change = adx_series[-1] - adx_series[-window]
    
    if adx_change > 2:
        return "ACCELERATING"
    elif adx_change < -2:
        return "DECELERATING"
    else:
        return "STABLE"

def detect_structure_break(bars, side="BUY", lookback=40):
    """
    判断结构破坏 (最近高低点是否开始反转)
    """
    if len(bars) < lookback:
        return "INTACT"
        
    recent_bars = bars[-lookback:]
    highs = [bar["high"] for bar in recent_bars]
    lows = [bar["low"] for bar in recent_bars]
    
    # Simple heuristic: split the lookback into two halves and compare their local extremes
    mid_point = len(recent_bars) // 2
    
    first_half_highs = sorted(highs[:mid_point])[-5:]
    second_half_highs = sorted(highs[mid_point:])[-5:]
    
    first_half_lows = sorted(lows[:mid_point])[:5]
    second_half_lows = sorted(lows[mid_point:])[:5]
    
    if not first_half_highs or not second_half_highs:
        return "INTACT"
        
    avg_fh_high = sum(first_half_highs) / len(first_half_highs)
    avg_sh_high = sum(second_half_highs) / len(second_half_highs)
    
    avg_fh_low = sum(first_half_lows) / len(first_half_lows)
    avg_sh_low = sum(second_half_lows) / len(second_half_lows)
    
    if side == "BUY":
        # 上涨趋势晚期：高点和低点都在下移
        if avg_sh_high < avg_fh_high and avg_sh_low < avg_fh_low:
            return "BREAKING"
    else:
        # 下跌趋势晚期：高点和低点都在上移
        if avg_sh_high > avg_fh_high and avg_sh_low > avg_fh_low:
            return "BREAKING"
            
    return "INTACT"

def trend_stage_score(bars, adx_series, rsi_series, side="BUY", ema21_v=None, atr_v=None):
    """
    组合三个维度，输出综合评分和阶段
    """
    divergence = detect_momentum_divergence(bars, rsi_series, side=side, atr_v=atr_v)
    adx_phase = adx_momentum(adx_series)
    structure = detect_structure_break(bars, side=side)
    
    score = 0
    if divergence == "EARLY_STAGE":
        score += 2
    elif divergence == "MIDDLE":
        score += 1
    elif divergence == "LATE_STAGE":
        score -= 3  # 增强背离的惩罚
        
    if adx_phase == "ACCELERATING":
        score += 1
    elif adx_phase == "DECELERATING":
        score -= 2
        
    if structure == "INTACT":
        score += 1
    elif structure == "BREAKING":
        score -= 2
        
    # 新增：乖离率过大直接判定为晚期（防止追高/追空接飞刀）
    if ema21_v is not None and len(bars) > 0:
        current_close = bars[-1]["close"]
        # 使用传入的真实 ATR（14周期平滑），如果没有则降级为单根波动
        current_atr = atr_v if atr_v and atr_v > 0 else (bars[-1]["high"] - bars[-1]["low"])
        # 护栏：价格偏离 EMA21 超过 1.5 个真实 ATR
        distance = abs(current_close - ema21_v)
        if distance > current_atr * 1.5:
            score -= 3
            
    # score 范围: -8 ~ +4
    if score >= 2:
        return "EARLY", score
    elif score >= 0:
        return "MIDDLE", score
    else:
        return "LATE", score
