"""
scanner_common.py — สูตรอินดิเคเตอร์และ pattern กลาง ใช้ร่วมกันทุกสแกนเนอร์
"""

from datetime import datetime
import pandas as pd

MARKET_CLOSE = {
    "US": (16, 0),
    "TH": (16, 30),
}


def calculate_rsi(series, period=14):
    delta = series.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    rs = gain / (loss + 1e-9)
    return 100 - (100 / (1 + rs))


def drop_incomplete_last_bar(df, market):
    if df is None or df.empty:
        return df, None
    try:
        idx = df.index
        tz = getattr(idx, "tz", None)
        now = datetime.now(tz) if tz is not None else datetime.now()
        last_date = idx[-1].date()
        if last_date != now.date():
            return df, None

        close_h, close_m = MARKET_CLOSE.get(market, (23, 59))
        already_closed = (now.hour, now.minute) >= (close_h, close_m)
        if already_closed:
            return df, None

        return df.iloc[:-1], (
            f"ตัดแท่งวันที่ {last_date} ทิ้ง (ตลาดยังไม่ปิด "
            f"{close_h:02d}:{close_m:02d}) -> ใช้แท่งที่ปิดแล้วล่าสุดแทน"
        )
    except Exception:
        return df, None


def rolling_high(df, window=250, min_periods=30):
    return df["High"].rolling(window=window, min_periods=min_periods).max()


def detect_liquidity_sweep(df, lookback=5):
    prev_low = df["Low"].shift(1).rolling(lookback).min()
    return ((df["Low"] < prev_low) & (df["Close"] > prev_low)).fillna(False)


def detect_hammer(df, wick_mult=1.5):
    body = (df["Close"] - df["Open"]).abs()
    rng = df["High"] - df["Low"]
    lower_wick = df[["Open", "Close"]].min(axis=1) - df["Low"]
    upper_wick = df["High"] - df[["Open", "Close"]].max(axis=1)

    return (
        (rng > 0)
        & (lower_wick >= wick_mult * body)
        & (lower_wick >= 0.40 * rng)
        & (upper_wick <= 0.35 * rng)
        & (df["Close"] > df["Low"] + 0.5 * rng)
    ).fillna(False)


def detect_bullish_engulfing(df):
    return (
        (df["Close"] > df["Open"])
        & (df["Close"].shift(1) < df["Open"].shift(1))
        & (df["Close"] >= df["Open"].shift(1))
        & (df["Open"] <= df["Close"].shift(1))
    ).fillna(False)


def detect_pa_reversal(df, wick_mult=1.5):
    return detect_hammer(df, wick_mult) | detect_bullish_engulfing(df)


def detect_volume_spike(df, window=20, threshold=2.0):
    """ตรวจจับ Volume Spike: Volume วันนี้ > threshold x เฉลี่ย window วันก่อน"""
    if df is None or len(df) < window + 1:
        return False
    avg_vol = df["Volume"].iloc[-(window + 1):-1].mean()
    latest_vol = df["Volume"].iloc[-1]
    if avg_vol <= 0:
        return False
    return float(latest_vol) > threshold * float(avg_vol)


def detect_volume_ratio(df, window=20):
    """คำนวณ ratio ของ Volume ล่าสุด vs เฉลี่ย (ใช้แสดงผล)"""
    if df is None or len(df) < window + 1:
        return 1.0
    avg_vol = df["Volume"].iloc[-(window + 1):-1].mean()
    latest_vol = df["Volume"].iloc[-1]
    if avg_vol <= 0:
        return 1.0
    return float(latest_vol) / float(avg_vol)


def detect_rsi_bullish_divergence(df, rsi_period=14, lookback=20):
    """
    ตรวจจับ RSI Bullish Divergence:
    - Price ทำ Lower Low (ราคาต่ำกว่าจุดต่ำสุดก่อนหน้า)
    - แต่ RSI ทำ Higher Low (RSI ไม่ได้ต่ำกว่าเดิม)
    → ขาลงอ่อนแรง มีโอกาสกลับตัว
    """
    if df is None or len(df) < lookback + 5:
        return False

    closes = df["Close"].values
    rsi_series = calculate_rsi(df["Close"], period=rsi_period).values

    # หาจุดต่ำสุดของราคาในช่วง lookback (ไม่รวม 5 แท่งล่าสุด)
    check_end = len(closes) - 5
    check_start = max(0, check_end - lookback)
    if check_end <= check_start:
        return False

    prev_low_idx = check_start + int(pd.Series(closes[check_start:check_end]).idxmin())
    prev_low_price = closes[prev_low_idx]
    prev_low_rsi = rsi_series[prev_low_idx]

    # ราคาล่าสุด vs จุดต่ำสุดเดิม
    current_price = closes[-1]
    current_rsi = rsi_series[-1]

    if pd.isna(prev_low_rsi) or pd.isna(current_rsi):
        return False

    # Bullish divergence: ราคาต่ำกว่าเดิม แต่ RSI สูงกว่าเดิม
    return current_price < prev_low_price and current_rsi > prev_low_rsi


def regime_min_score(regime, base_score=2, mode="raise_bar"):
    if mode == "off" or regime != "BEAR":
        return base_score
    if mode == "block":
        return 99
    return 3


def make_verdict(drawdown, rsi, sweep, pa, ema, score, news_text="",
                 volume_spike=False, rsi_divergence=False, vol_ratio=1.0):
    """
    สร้างข้อความวิเคราะห์แบบ rule-based (ไม่ใช้ AI)
    ใช้ค่า RSI / drawdown / สัญญาณที่คำนวณได้จริง มาประกอบเป็นคำอธิบาย
    ผลลัพธ์คงที่ทุกครั้งที่รัน (deterministic)
    """
    # 1) โซน RSI
    if rsi <= 30:
        rsi_txt = f"RSI {rsi:.0f} ต่ำมาก (oversold) เข้าโซนของถูก"
    elif rsi <= 40:
        rsi_txt = f"RSI {rsi:.0f} เริ่มต่ำ มีโอกาสกลับตัว"
    elif rsi <= 50:
        rsi_txt = f"RSI {rsi:.0f} ปานกลาง ยังไม่สุดทาง"
    elif rsi <= 70:
        rsi_txt = f"RSI {rsi:.0f} ปกติ"
    else:
        rsi_txt = f"RSI {rsi:.0f} สูง (overbought) ระวังย่อ"

    # 2) สัญญาณกลับตัวที่ตรวจพบ
    sigs = []
    if sweep:
        sigs.append("กวาดสภาพคล่อง")
    if pa:
        sigs.append("แท่งกลับตัว")
    if ema:
        sigs.append("ยืนเหนือ EMA9")
    if volume_spike:
        sigs.append(f"🔥 Volume {vol_ratio:.1f}x (spike)")
    sig_txt = " + ".join(sigs) if sigs else "ยังไม่มีสัญญาณกลับตัว"

    # 3) ตัวเสริม (RSI Divergence)
    extras = []
    if rsi_divergence:
        extras.append("📈 RSI Divergence — ขาลงอ่อนแรง")
    extra_txt = " | ".join(extras) if extras else ""

    # 4) หัวข้อตามคะแนน (4 สัญญาณ: Sweep/PA/EMA/Vol)
    if score >= 4:
        head = "✨ สัญญาณครบ 4 ด้าน (Prime Setup)"
    elif score == 3:
        head = "✨ สัญญาณ 3/4 แข็งแรง"
    elif score == 2:
        head = "✨ สัญญาณ 2/4 น่าสนใจ"
    else:
        head = "○ รอสัญญาณเพิ่มเติม"

    result = f"{head}: {rsi_txt} | {sig_txt}"
    if extra_txt:
        result += f" | {extra_txt}"
    return result
