#!/usr/bin/env python3
"""
review_notify.py — 复核信号即时通知
当 review_pending 有新信号时，立即通知 Agent 决策
不等待 cron 定时
"""
import json, sys, pathlib, time
from datetime import datetime
import os

# Add parent directory to sys.path to import config_manager
sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.absolute()))
from config_manager import get_logs_dir

# ROOT now resolved via frozen_path (PyInstaller-safe)
from frozen_path import APP_ROOT as ROOT
LOG_DIR    = get_logs_dir()
REVIEW_DIR = LOG_DIR / "review_pending"
STATE_FILE = LOG_DIR / ".agent_state.json"


def _now():
    return datetime.now().strftime("%Y-%m-%dT%H:%M:%S+08:00")


def _read_gateway_token() -> str:
    """Read gateway token from file or env. Avoid hardcoding."""
    token = os.environ.get("OPENCLAW_GATEWAY_TOKEN", "")
    if token:
        return token
    token_file = pathlib.Path.home() / ".openclaw" / "gateway.token"
    if token_file.exists():
        try:
            return token_file.read_text(encoding="utf-8").strip()
        except Exception:
            pass
    return ""


def _load_json(path, default=None):
    if not path.exists():
        return default or {}
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except:
        return default or {}

def get_pending_signals():
    """读取所有待复核信号"""
    if not REVIEW_DIR.exists():
        return []
    signals = []
    for f in sorted(REVIEW_DIR.glob("*.review.json"), key=lambda x: x.stat().st_mtime, reverse=True):
        try:
            d = json.loads(f.read_text(encoding="utf-8"))
            age_secs = time.time() - f.stat().st_mtime
            signals.append({**d, "_file": f.name, "_age_secs": age_secs})
        except:
            pass
    return signals

def build_notify_message(sig):
    """为单条信号构建通知消息"""
    side = sig.get("side", "?")
    action = sig.get("action", "?")
    conf = sig.get("confidence", 0)
    conf_pct = round(conf * 100, 1)
    regime = sig.get("regime", "?")
    indicators = sig.get("indicators", {})
    entry = sig.get("entry", 0)
    sl = sig.get("sl", 0)
    tp = sig.get("tp", 0)
    rsi = indicators.get("rsi14", "?")
    adx = indicators.get("adx", "?")
    age_mins = round(sig.get("_age_secs", 0) / 60, 1)

    return f"""[BELL] 【需要Agent拍板】信号复核请求

[TIME] 到期时间：{age_mins}分钟前

[LIST] 信号详情：
  操作：{action} {side}
  置信度：{conf_pct}%
  格局：{regime}
  入场：{entry}
  止损：{sl}
  止盈：{tp}

[STATS] 技术指标：
  RSI={rsi} | ADX={adx}
  EMA9={indicators.get('ema9', '?')} | EMA21={indicators.get('ema21', '?')}

[WARN]️ 请立即决策：
Approve → 写入 logs/review_pending/approve/{sig['signal_id']}.json
Reject  → 写入 logs/review_pending/reject/{sig['signal_id']}.json"""

def notify_via_gateway(session_key, message):
    """通过 OpenClaw Gateway API 向 Agent 主会话发消息（实时）"""
    try:
        import urllib.request, json as json2
        gateway_token = _read_gateway_token()
        gateway_host = os.environ.get("OPENCLAW_GATEWAY_HOST", "127.0.0.1:18789")
        payload = {
            "method": "session.send",
            "params": {
                "sessionKey": session_key,
                "message": message
            }
        }
        req = urllib.request.Request(
            f"http://{gateway_host}",
            data=json2.dumps(payload).encode(),
            headers={
                "Authorization": f"Bearer {gateway_token}",
                "Content-Type": "application/json"
            },
            method="POST"
        )
        with urllib.request.urlopen(req, timeout=5) as r:
            resp = json2.loads(r.read())
            return resp.get("ok", False)
    except Exception as e:
        print(f"[review_notify] Gateway通知失败: {e}")
        return False

def notify_via_qq(message):
    """通过 OpenClaw Gateway 推送通知给 Agent"""
    # 写入通知文件（供后续处理）
    notify_file = LOG_DIR / f"review_notify_{int(time.time())}.json"
    try:
        notify_file.write_text(json.dumps({
            "type": "review_pending",
            "message": message,
            "timestamp": _now(),
        }, ensure_ascii=False))
        print(f"[review_notify] 已写入通知: {notify_file.name}")
    except Exception as e:
        print(f"[review_notify] 写入通知文件失败: {e}")

    # 尝试通过 Gateway 发给 Agent 主会话
    gateway_token_file = pathlib.Path.home() / ".openclaw/gateway.token"
    if gateway_token_file.exists():
        gateway_token = gateway_token_file.read_text(encoding="utf-8").strip()
    else:
        gateway_token = ""  # fallback

    # 通过 OpenClaw 的 message tool 格式写入临时文件，让 gateway 处理
    # 这里写入一个触发文件，通知主 session 有紧急复核
    trigger_file = LOG_DIR / "agent_review_trigger.json"
    try:
        trigger_file.write_text(json.dumps({
            "type": "URGENT_REVIEW",
            "message": message,
            "timestamp": _now(),
            "notify_via": "qq",
        }, ensure_ascii=False))
        print(f"[review_notify] 已写入触发文件: {trigger_file.name}")
    except Exception as e:
        print(f"[review_notify] 写入触发文件失败: {e}")

    print(f"[review_notify] 通知已就绪，等待 Agent 处理")
    return True

def spawn_review_agent(sig):
    """触发 review cron 立即运行"""
    try:
        import subprocess
        # 触发 review cron 立即执行
        result = subprocess.run([
            "openclaw", "cron", "run",
            "ec5747c1-23a5-43e0-823f-bce1c181b522"
        ], capture_output=True, text=True, timeout=10)
        print(f"[review_notify] cron立即触发: exit={result.returncode}")
        if result.stdout:
            print(f"  stdout: {result.stdout[:100]}")
        if result.stderr:
            print(f"  stderr: {result.stderr[:100]}")
        return result.returncode == 0
    except Exception as e:
        print(f"[review_notify] cron触发失败: {e}")
        return False

def run():
    signals = get_pending_signals()
    if not signals:
        print(f"[review_notify] 无待复核信号")
        return

    newest = signals[0]
    print(f"[review_notify] 发现 {len(signals)} 条待复核信号")

    # 立即 spawn Agent 决策最新的信号
    if newest.get('_age_secs', 9999) < 300:  # 5分钟内的才spawn
        msg = build_notify_message(newest)
        print(f"\n[review_notify] 立即触发 Agent 决策...")
        spawn_review_agent(newest)
    else:
        print(f"[review_notify] 信号过老({newest.get('_age_secs',0)//60}分钟)，等待cron处理")

    # 写入状态
    state = _load_json(STATE_FILE)
    state["review_pending_count"] = len(signals)
    state["review_pending_latest"] = newest.get("signal_id")
    state["review_pending_updated"] = _now()
    STATE_FILE.write_text(json.dumps(state, indent=2))

def run_text_notify(message: str):
    LOG_DIR.mkdir(parents=True, exist_ok=True)
    notify_via_qq(message)
    return True

if __name__ == "__main__":
    if len(sys.argv) >= 3 and sys.argv[1] == "--text":
        run_text_notify(" ".join(sys.argv[2:]))
    else:
        run()
