#!/usr/bin/env python3
"""
Parallel Analysis Engine - M2.7 指挥官调用的并行分析引擎
同时执行多个分析模块，结果汇总给 M2.7 做综合决策
"""
import json, time, sys, pathlib
from concurrent.futures import ThreadPoolExecutor, as_completed

ROOT = pathlib.Path(__file__).parent.parent.absolute()
sys.path.insert(0, str(ROOT))
BRIDGE = ROOT / "bridge"

# ============ 各分析模块 ============

def analyze_technical():
    """技术分析"""
    try:
        import subprocess
        result = subprocess.run(
            ["python3", str(BRIDGE / "strategy.py")],
            capture_output=True, text=True, timeout=30, cwd=str(ROOT)
        )
        return {"module": "technical", "status": "ok", "output": result.stdout[:2000], "error": result.stderr[:500] if result.stderr else ""}
    except Exception as e:
        return {"module": "technical", "status": "error", "error": str(e)}

def analyze_sessions():
    """多时段分析"""
    try:
        import subprocess
        result = subprocess.run(
            ["python3", str(BRIDGE / "session_analyzer.py")],
            capture_output=True, text=True, timeout=30, cwd=str(ROOT)
        )
        return {"module": "sessions", "status": "ok", "output": result.stdout[:2000], "error": ""}
    except Exception as e:
        return {"module": "sessions", "status": "error", "error": str(e)}

def analyze_trade_performance():
    """交易绩效分析"""
    try:
        from skill_trading_memory import query_trades, query_signals, query_risk_events
        trades = query_trades(limit=100, since_days=7) or []
        signals = query_signals(limit=100, since_days=7) or []
        risks = query_risk_events(limit=100, since_days=7) or []

        if not trades:
            # 尝试从 decision_ledger 读取历史信号
            try:
                dl = ROOT / "logs" / "decision_ledger.ndjson"
                if dl.exists():
                    lines = dl.read_text().strip().split("\n")
                    entries = [json.loads(l) for l in lines if l.strip()]
                    approved = [e for e in entries if e.get("category") == "signal_envelope" and e.get("payload", {}).get("signal", {}).get("governor_status") == "APPROVED"]
                    return {"module": "performance", "status": "no_trades", "signals_approved": len(approved), "risk_events": len(risks)}
            except:
                pass
            return {"module": "performance", "status": "no_trades", "risk_events": len(risks)}

        wins = [t for t in trades if t.get("pnl", 0) > 0]
        losses = [t for t in trades if t.get("pnl", 0) <= 0]
        win_rate = len(wins) / len(trades) * 100 if trades else 0
        total_pnl = sum(t.get("pnl", 0) for t in trades)
        avg_win = sum(t.get("pnl", 0) for t in wins) / len(wins) if wins else 0
        avg_loss = abs(sum(t.get("pnl", 0) for t in losses) / len(losses)) if losses else 0
        rr_ratio = avg_win / avg_loss if avg_loss > 0 else 0

        tp_hits = [t for t in trades if t.get("close_reason") == "TP"]
        sl_hits = [t for t in trades if t.get("close_reason") == "SL"]
        tp_rate = len(tp_hits) / len(trades) * 100 if trades else 0

        return {
            "module": "performance",
            "status": "ok",
            "data": {
                "total_trades": len(trades),
                "wins": len(wins),
                "losses": len(losses),
                "win_rate": round(win_rate, 1),
                "total_pnl": round(total_pnl, 2),
                "avg_win": round(avg_win, 2),
                "avg_loss": round(avg_loss, 2),
                "rr_ratio": round(rr_ratio, 2),
                "tp_hits": len(tp_hits),
                "sl_hits": len(sl_hits),
                "tp_rate": round(tp_rate, 1),
                "recent_signals": len(signals),
                "risk_events": len(risks),
            }
        }
    except Exception as e:
        return {"module": "performance", "status": "error", "error": str(e)}

def analyze_position_risk():
    """持仓风险分析"""
    try:
        MT5_COMMON = pathlib.Path.home() / "Library/Application Support/net.metaquotes.wine.metatrader5/drive_c/users/user/AppData/Roaming/MetaQuotes/Terminal/Common/Files"
        state_file = ROOT / "logs" / ".agent_state.json"
        terminal_file = MT5_COMMON / "gold_autotrade/bridge/terminal_status.json"

        state = {}
        if state_file.exists():
            state = json.loads(state_file.read_text())

        terminal = {}
        if terminal_file.exists():
            terminal = json.loads(terminal_file.read_text())

        return {
            "module": "position_risk",
            "status": "ok",
            "data": {
                "position_open": state.get("position_open", False),
                "position_side": state.get("position_side", "NONE"),
                "position_entry": state.get("position_entry", 0),
                "position_sl": state.get("position_sl", 0),
                "position_tp": state.get("position_tp", 0),
                "position_vol": state.get("position_vol", 0),
                "kill_switch": state.get("kill_switch", False),
                "consecutive_losses": state.get("consecutive_losses", 0),
                "terminal_positions": terminal.get("positions", []),
                "account_balance": terminal.get("balance", "?"),
                "spread": terminal.get("spread", "?"),
            }
        }
    except Exception as e:
        return {"module": "position_risk", "status": "error", "error": str(e)}

def analyze_market_forecast():
    """市场预测（基于近期数据）"""
    try:
        import subprocess
        result = subprocess.run(
            ["python3", "-c", """
import pathlib, sys
ROOT = pathlib.Path(__file__).parent.parent.absolute()
sys.path.insert(0, str(ROOT))
from bridge.strategy import get_data, compute_indicators, detect_regime

df = get_data()
if df is None or df.empty:
    print('NO_DATA')
    sys.exit()
df = compute_indicators(df)
regime = detect_regime(df)
latest = df.iloc[-1]
rsi = latest.get('rsi', 50)
adx = latest.get('adx', 0)
bb_upper = latest.get('bb_upper', 0)
bb_lower = latest.get('bb_lower', 0)
bb_mid = latest.get('bb_mid', 0)
close = latest.get('close', 0)
ema9 = latest.get('ema9', 0)
ema21 = latest.get('ema21', 0)
macd = latest.get('macd', 0)
signal = latest.get('signal', 0)
print(f'RSI={rsi:.1f} ADX={adx:.1f} BB_upper={bb_upper:.1f} close={close:.1f} ema9={ema9:.1f} ema21={ema21:.1f} MACD={macd:.2f} signal={signal:.2f} regime={regime}')
"""],
            capture_output=True, text=True, timeout=30
        )
        return {"module": "forecast", "status": "ok", "output": result.stdout.strip(), "error": result.stderr[:300] if result.stderr else ""}
    except Exception as e:
        return {"module": "forecast", "status": "error", "error": str(e)}

# ============ 主引擎 ============

def run_parallel_analysis(timeout=60):
    """并行执行所有分析模块"""
    start = time.time()
    modules = [
        ("technical", analyze_technical),
        ("sessions", analyze_sessions),
        ("performance", analyze_trade_performance),
        ("position_risk", analyze_position_risk),
        ("forecast", analyze_market_forecast),
    ]

    results = {}
    with ThreadPoolExecutor(max_workers=5) as executor:
        futures = {executor.submit(func): name for name, func in modules}
        for future in as_completed(futures, timeout=timeout):
            name = futures[future]
            try:
                results[name] = future.result()
            except Exception as e:
                results[name] = {"module": name, "status": "error", "error": str(e)}

    elapsed = time.time() - start
    return {
        "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
        "elapsed_seconds": round(elapsed, 1),
        "results": results,
        "summary": _build_summary(results),
    }

def _build_summary(results):
    """构建摘要供 M2.7 快速参考"""
    lines = ["=== 5维度并行分析摘要 ==="]
    for name, r in results.items():
        status = r.get("status", "?")
        if status == "ok":
            if "data" in r:
                d = r["data"]
                if name == "performance":
                    lines.append(f"[{name}] 交易: {d.get('total_trades',0)}笔 胜率{d.get('win_rate',0)}% TP命中率{d.get('tp_rate',0)}% 总盈亏${d.get('total_pnl',0)} 风险事件{d.get('risk_events',0)}")
                elif name == "position_risk":
                    pos = "有持仓" if d.get("position_open") else "无持仓"
                    lines.append(f"[{name}] {pos} 方向={d.get('position_side')} 连亏={d.get('consecutive_losses')} KillSwitch={d.get('kill_switch')}")
            elif "output" in r:
                out = r["output"]
                if out:
                    lines.append(f"[{name}] {out[:250]}")
                else:
                    lines.append(f"[{name}] (无输出)")
        elif status == "no_trades":
            if name == "performance":
                lines.append(f"[{name}] 无交易记录 | 已批准信号:{r.get('signals_approved',0)} 风险事件:{r.get('risk_events',0)}")
            else:
                lines.append(f"[{name}] status={status}")
        else:
            err = r.get("error", "unknown")
            lines.append(f"[{name}] ERROR: {str(err)[:100]}")
    return "\n".join(lines)

if __name__ == "__main__":
    output_file = ROOT / "logs" / "parallel_analysis_latest.json"
    output_file.parent.mkdir(parents=True, exist_ok=True)

    report = run_parallel_analysis(timeout=55)

    # 写入结果文件
    output_file.write_text(json.dumps(report, indent=2, ensure_ascii=False))

    # 同时输出摘要到 stdout
    print(report["summary"])
    print(f"\n耗时: {report['elapsed_seconds']}秒")
    print(f"详情: {output_file}")

    # ============ 调用参数建议引擎 ============
    import subprocess
    print("\n--- 参数建议 ---")
    r = subprocess.run(
        ["python3", str(ROOT / "bridge" / "params_advisor.py")],
        capture_output=True, text=True, timeout=15, cwd=str(ROOT)
    )
    print(r.stdout)
    if r.stderr:
        print("STDERR:", r.stderr[:300])
