#!/usr/bin/env python3
"""
Signal Pusher - 主动向 QQ 推送高置信度交易信号
触发条件：底层 composite 信号置信度 >= CONFIDENCE_THRESHOLD 且方向与 Agent 方向一致
"""
import sys, json, time, re, pathlib
from datetime import datetime, timedelta
from pathlib import Path

try:
    from src.market_context import normalize_regime_label
except ModuleNotFoundError:
    from market_context import normalize_regime_label

# ROOT now resolved via frozen_path (PyInstaller-safe)
from frozen_path import APP_ROOT as ROOT
# LOG_DIR now resolved via frozen_path
from frozen_path import LOGS_DIR as LOG_DIR
STATE_FILE = LOG_DIR / ".signal_push_state.json"
CONF_THRESHOLD = 0.80  # 80% 置信度触发推送

QQ_TARGET = "qqbot:c2c:260433477"

def load_state():
    if STATE_FILE.exists():
        with open(STATE_FILE, encoding="utf-8") as f:
            return json.load(f)
    return {"last_push_time": None, "last_signal_hash": None}

def save_state(state):
    with open(STATE_FILE, "w", encoding="utf-8") as f:
        json.dump(state, f, indent=2)

def get_today_log():
    today = datetime.now().strftime("%Y%m%d")
    return LOG_DIR / f"gold_trader.{today}.log"

def parse_recent_signals(log_path, minutes=10):
    """解析最近 N 分钟的信号，返回高置信度信号列表"""
    if not log_path.exists():
        return []

    content = log_path.read_text(encoding="utf-8")
    lines = content.split("\n")
    cutoff = datetime.now() - timedelta(minutes=minutes)

    signals = []
    for line in reversed(lines[-200:]):
        if "Signal:" not in line:
            continue
        try:
            # Extract timestamp: [HH:MM:SS]
            ts_match = re.search(r"\[(\d{2}:\d{2}:\d{2})\]", line)
            if not ts_match:
                continue
            ts_str = ts_match.group(1)
            today_str = datetime.now().strftime("%Y-%m-%d")
            ts = datetime.strptime(f"{today_str} {ts_str}", "%Y-%m-%d %H:%M:%S")
            if ts < cutoff:
                continue

            # Extract action: OPEN BUY / OPEN SELL / HOLD
            action_match = re.search(r"Signal: (OPEN\s+(BUY|SELL)|HOLD)", line)
            if not action_match:
                continue
            action = action_match.group(1)

            # Extract confidence: eff_conf=XX%
            conf_match = re.search(r"eff_conf=([\d.]+)%", line)
            confidence = float(conf_match.group(1)) / 100 if conf_match else 0

            # Extract regime
            regime_match = re.search(
                r"\| (RANGING|WEAK_TREND|STRONG_TREND|STEALTH_TREND|TRANSITION|VOLATILITY_SPIKE|FAKE_TREND|EXTREME) \|",
                line,
            )
            regime = normalize_regime_label(regime_match.group(1)) if regime_match else "?"

            # Extract price
            price_match = re.search(r"XAUUSD ([\d.]+)/([\d.]+)", line)
            price = f"{price_match.group(1)}/{price_match.group(2)}" if price_match else "?"

            # Extract composite sub-signals
            composite_match = re.search(r"(Composite BUY|Composite SELL|多头共振|空头共振|[0-9]+共振)", line)

            signals.append({
                "action": action,
                "confidence": confidence,
                "regime": regime,
                "price": price,
                "time": ts_str,
                "line": line.strip()
            })
        except Exception:
            continue

    return signals

def format_qq_message(signal):
    direction = signal["action"].replace("OPEN ", "")
    side_flag = "[BUY]" if "BUY" in signal["action"] else "[SELL]" if "SELL" in signal["action"] else "[HOLD]"

    return f"""[XAUUSD High Confidence Signal] {side_flag}
Time: {signal['time']} | Regime: {signal['regime']}
Direction: {direction}
Confidence: {signal['confidence']*100:.0f}%
Price: {signal['price']}

For reference only. Not investment advice."""

def push_to_qq(message):
    """写入待推送纯文本，cron job 读取后通过 announce 发送到 QQ"""
    push_file = LOG_DIR / ".pending_qq_push.txt"
    with open(push_file, "w", encoding="utf-8") as f:
        f.write(message)
    print(f"[{datetime.now().strftime('%H:%M:%S')}] QQ push queued: {message[:50]}...")

def run():
    state = load_state()
    log_path = get_today_log()

    # 只处理最近 5 分钟的信号，避免重复推送同一信号
    signals = parse_recent_signals(log_path, minutes=5)

    pushed = False
    for sig in signals:
        # Skip HOLD
        if "HOLD" in sig["action"]:
            continue

        # Skip low confidence
        if sig["confidence"] < CONF_THRESHOLD:
            continue

        # Build signal hash to avoid duplicate pushes
        sig_hash = f"{sig['action']}_{sig['time']}_{sig['confidence']}"
        if sig_hash == state.get("last_signal_hash"):
            continue

        # Rate limit: don't push more than once per 30 minutes
        if state.get("last_push_time"):
            last_push = datetime.fromisoformat(state["last_push_time"])
            if (datetime.now() - last_push).seconds < 1800:
                continue

        # Push!
        msg = format_qq_message(sig)
        push_to_qq(msg)

        state["last_push_time"] = datetime.now().isoformat()
        state["last_signal_hash"] = sig_hash
        save_state(state)
        pushed = True
        print(f"[{datetime.now().strftime('%H:%M:%S')}] [OK] Pushed signal: {sig['action']} @ {sig['confidence']*100:.0f}%")
        break  # Only push one per run

    if not pushed:
        print(f"[{datetime.now().strftime('%H:%M:%S')}] No high-confidence signal to push (checked {len(signals)} recent signals)")

if __name__ == "__main__":
    run()
