import json
import time
import os
import sys
from datetime import datetime, timedelta
import pathlib

# ROOT now resolved via frozen_path (PyInstaller-safe)
from frozen_path import APP_ROOT as ROOT
sys.path.insert(0, str(ROOT))
import config_manager

LOGS_DIR = config_manager.get_logs_dir()
TRADING_LEDGER = LOGS_DIR / "trading_ledger.ndjson"
GARCH_CACHE = LOGS_DIR / "garch_volatility_cache.json"

def generate_morning_briefing():
    today = datetime.now()
    yesterday_str = (today - timedelta(days=1)).strftime("%Y-%m-%d")
    
    # 1. 统计昨晚盈亏
    total_pnl = 0.0
    trades_count = 0
    win_count = 0
    
    if TRADING_LEDGER.exists():
        with open(TRADING_LEDGER, "r", encoding="utf-8") as f:
            for line in f:
                if not line.strip(): continue
                try:
                    data = json.loads(line)
                    # 支持解析带有 ISO 格式（含 T 和时区）的时间字符串
                    ts = data.get("ts", "")
                    
                    # 兼容性修复：如果早报今天（25号）跑，统计的是昨天（24号）
                    # 但我们刚跑出的数据可能记录的是今天的日期（跨过了零点）
                    # 为了测试效果，我们放宽统计条件，把最近24小时内的数据都算进来
                    
                    data_pnl = float(data.get("pnl", 0) or 0)
                    # 修复：理论盈亏兜底计算 (和 gui_backend 保持一致)
                    if data_pnl == 0:
                        entry_price = float(data.get("entry", 0) or 0)
                        exit_price = float(data.get("exit", 0) or 0)
                        vol = float(data.get("volume", 0) or 0)
                        side = data.get("side", "")
                        
                        # 对于 RECOVERED 的数据，如果没有 exit 价格，就无法计算真实盈亏
                        # 我们只能把它算作一笔订单，但盈亏不计入（或者您如果知道它是被打损的，可以估算）
                        if entry_price > 0 and exit_price > 0 and vol > 0:
                            if side == "BUY":
                                data_pnl = (exit_price - entry_price) * 100 * vol
                            elif side == "SELL":
                                data_pnl = (entry_price - exit_price) * 100 * vol
                                
                    try:
                        # 兼容带微秒和不带微秒的 ISO 格式，将其转换为本地时间判断
                        ts_clean = ts.replace("Z", "+00:00")
                        record_time_utc = datetime.fromisoformat(ts_clean)
                        # 如果解析后没有时区信息，默认其为 UTC
                        if record_time_utc.tzinfo is None:
                            from datetime import timezone
                            record_time_utc = record_time_utc.replace(tzinfo=timezone.utc)
                        
                        record_time_local = record_time_utc.astimezone()
                        
                        # 精确匹配“昨天”的本地日期，拒绝使用模糊的 48 小时
                        if record_time_local.strftime("%Y-%m-%d") == yesterday_str:
                            # 过滤掉恢复的幽灵数据，只统计真实有 PnL 的数据
                            if abs(data_pnl) > 0.01: 
                                total_pnl += data_pnl
                                trades_count += 1
                                if data_pnl > 0: win_count += 1
                    except Exception as e:
                        # 降级方案：直接字符串匹配昨天日期
                        if yesterday_str in ts:
                            if abs(data_pnl) > 0.01:
                                total_pnl += data_pnl
                                trades_count += 1
                                if data_pnl > 0: win_count += 1
                except:
                    pass
                    
    win_rate = (win_count / trades_count * 100) if trades_count > 0 else 0.0
    
    # ── 数据完整性检查 ──────────────────────────────────────
    # 如果 ledger 里昨天没有记录，但 signal_ledger 显示有 OPEN/CLOSE 信号，
    # 说明 ledger 写入可能断了，需要补录
    data_quality_warning = ""
    SIGNAL_LEDGER = LOGS_DIR / "signal_ledger.ndjson"
    if SIGNAL_LEDGER.exists() and SIGNAL_LEDGER.stat().st_size > 0:
        trade_signals_yesterday = 0
        with open(SIGNAL_LEDGER, "r", encoding="utf-8") as f:
            for line in f:
                try:
                    d = json.loads(line)
                    ts = d.get("ts", d.get("timestamp", ""))
                    if (
                        yesterday_str in ts
                        and d.get("action") in ("OPEN", "CLOSE")
                        and d.get("result") not in ("GENERATED", "N/A")
                    ):
                        trade_signals_yesterday += 1
                except:
                    pass
        if trade_signals_yesterday > 0 and trades_count == 0:
            data_quality_warning = (
                f"[WARN]️ 数据警告：昨日 signal_ledger 有 {trade_signals_yesterday} 个交易信号，"
                f"但 trading_ledger 无成交记录（可能存在写入断层）。"
                f"建议运行: python3 bridge/recover_ledger_from_snapshots.py --date {yesterday_str}"
            )
    
    # 2. 统计昨晚信号质量（OPEN/CLOSE 之外的状态信号）
    signals_count = 0
    blocked_count = 0
    
    if SIGNAL_LEDGER.exists():
        with open(SIGNAL_LEDGER, "r", encoding="utf-8") as f:
            for line in f:
                try:
                    data = json.loads(line)
                    ts = data.get("timestamp", data.get("ts", ""))
                    if ts.startswith(yesterday_str) or yesterday_str in ts:
                        signals_count += 1
                        if data.get("action") == "HOLD" or "BLOCKED" in data.get("reason", ""):
                            blocked_count += 1
                except:
                    pass
    
    # 3. 获取早盘波动率
    vol_regime = "UNKNOWN"
    vol_multiplier = 1.0
    if GARCH_CACHE.exists():
        try:
            with open(GARCH_CACHE, "r", encoding="utf-8") as f:
                garch = json.load(f)
                vol_regime = garch.get("regime", "UNKNOWN")
                vol_multiplier = garch.get("multiplier", 1.0)
        except:
            pass
            
    prompt = f"""
请作为黄金量化交易系统的 AI 助理（龙虾 Agent），生成一份今天的早间简报（Morning Briefing）。
时间：{today.strftime("%Y-%m-%d %H:%M")}
昨日交易统计：共交易 {trades_count} 笔，胜率 {win_rate:.1f}%，总盈亏 {total_pnl:.2f} 美元。
今日早盘波动率状态：{vol_regime} (乘数: {vol_multiplier:.2f})。
{data_quality_warning}

请用专业、机智、带有数字伴侣关怀感的语气，向老板汇报昨晚的战况，并给出今天开盘的参数建议（例如是否需要调宽网格或采取保守模式）。字数控制在 150 字以内。
"""
    print("=== M2 Morning Briefing Prompt ===")
    print(prompt)
    
    # 触发 OpenClaw Agent
    try:
        import subprocess
        import shutil
        
        # 确保 cron 环境下能找到 openclaw
        env = os.environ.copy()
        openclaw_bin = "openclaw"
        try:
            if sys.platform == "win32":
                bin_path_file = pathlib.Path(os.environ.get("APPDATA", "")) / "LobsterQuant" / "openclaw_bin_path.txt"
            else:
                bin_path_file = pathlib.Path.home() / "Library" / "Application Support" / "LobsterQuant" / "openclaw_bin_path.txt"
            if bin_path_file.exists():
                openclaw_bin = bin_path_file.read_text(encoding="utf-8").strip()
                # 确保父目录在 PATH 中
                bin_dir = str(pathlib.Path(openclaw_bin).parent)
                env["PATH"] = f"{bin_dir}{';' if sys.platform == 'win32' else ':'}{env.get('PATH', '/usr/local/bin:/usr/bin:/bin')}"
        except Exception as e:
            print(f"Failed to read openclaw bin path: {e}")

        if sys.platform == "win32":
            npm_global_bin = os.path.expanduser("~\\AppData\\Roaming\\npm")
            env["PATH"] = f"{npm_global_bin};{env.get('PATH', '')}"
        else:
            npm_global_bin = os.path.expanduser("~/Documents/trae_projects/.npm-global/bin")
            homebrew_bin = "/opt/homebrew/bin"
            env["PATH"] = f"{npm_global_bin}:{homebrew_bin}:{env.get('PATH', '/usr/local/bin:/usr/bin:/bin')}"
        
        openclaw_bin = shutil.which("openclaw", path=env["PATH"]) or openclaw_bin
        
        print(f"Calling OpenClaw Agent using {openclaw_bin}...")
        result = subprocess.run([
            openclaw_bin, "agent", 
            "--session-id", "gold-morning-briefing", 
            "--message", prompt,
            "--json"
        ], capture_output=True, text=True, env=env)
        
        # 尝试解析 JSON 提取纯净文本
        reply_text = result.stdout
        try:
            # openclaw agent --json 的输出可能包含前置日志，找第一个 { 开始的完整 JSON
            stdout_str = result.stdout
            start_idx = stdout_str.find('{')
            if start_idx != -1:
                json_str = stdout_str[start_idx:]
                data = json.loads(json_str)
                if "result" in data and "payloads" in data["result"]:
                    payloads = data["result"]["payloads"]
                    if payloads and "text" in payloads[0]:
                        reply_text = payloads[0]["text"]
        except Exception as e:
            print("Failed to parse JSON:", e)
            
        print("OpenClaw Output:", reply_text)
        if result.stderr:
            print("OpenClaw Error:", result.stderr)
            
        # 可选：将生成的早报存入日志，供前端 Timeline 读取
        report_file = LOGS_DIR / "morning_briefing_latest.md"
        report_text = f"时间: {today.strftime('%Y-%m-%d %H:%M')}\n\n{reply_text}"
        report_file.write_text(report_text)
        
        # 将生成的早报推送到飞书
        try:
            print("Pushing to Feishu...")
            feishu_result = subprocess.run([
                openclaw_bin, "message", "send",
                "--channel", "feishu",
                "--target", "user:ou_da360f293c9de80d9e9f80df32fdc877", 
                "--message", report_text
            ], capture_output=True, text=True, env=env)
            print("Feishu Push Output:", feishu_result.stdout)
        except Exception as e:
            print(f"Failed to push to Feishu: {e}")

        # 将生成的早报推送到 QQ
        try:
            print("Pushing to QQ...")
            qq_result = subprocess.run([
                openclaw_bin, "message", "send",
                "--channel", "qqbot",
                "--target", "qqbot:c2c:6458DEC5ADA70D568AE130C637565052", 
                "--message", report_text
            ], capture_output=True, text=True, env=env)
            print("QQ Push Output:", qq_result.stdout)
        except Exception as e:
            print(f"Failed to push to QQ: {e}")
            
    except Exception as e:
        print(f"Failed to call openclaw agent: {e}")
        
    return prompt

if __name__ == "__main__":
    generate_morning_briefing()
