#!/usr/bin/env python3
"""
DeepSeek Agent — 第一层：宏观战略定调 (The Commander)

职责：
每隔数小时触发，结合 session_analyzer 的多时段数据和宏观上下文，
调用 DeepSeek API，生成当天的宏观交易方向，
并写入 gold_trader 系统的 direction 决策中。

输出指令：
- LONG (只准做多)
- NEUTRAL (震荡/无方向，允许底层双向交易)
注意：宏观层面只做多，禁止输出 SHORT。
"""

import json
import os
import sys
import pathlib
import time

# 设置项目根目录
ROOT = pathlib.Path(__file__).parent.parent.absolute()
sys.path.insert(0, str(ROOT))

import requests

from bridge.session_analyzer import analyze_all_sessions
from bridge.gold_trader import save_agent_direction


def _get_api_key() -> str:
    api_key = os.environ.get("DEEPSEEK_API_KEY", "")
    if api_key:
        return api_key
    try:
        import config_manager
        app_config = config_manager.load_app_config()
        api_key = app_config.get("DEEPSEEK_API_KEY", "")
    except Exception:
        pass
    return api_key


def extract_json_block(text):
    """从 LLM 的回复文本中安全提取 JSON"""
    start_idx = text.find('{')
    end_idx = text.rfind('}')
    if start_idx != -1 and end_idx != -1:
        try:
            return json.loads(text[start_idx:end_idx+1])
        except Exception:
            pass
    return None


def _call_deepseek_api(prompt: str, api_key: str, timeout: int = 120) -> str:
    """Call DeepSeek API directly and return the response text."""
    resp = requests.post(
        "https://api.deepseek.com/v1/chat/completions",
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        json={
            "model": "deepseek-v4-flash",
            "messages": [
                {"role": "system", "content": "You are a strategic macro commander for a gold (XAUUSD) algorithmic trading system. You make directional decisions based on technical data. Always output valid JSON."},
                {"role": "user", "content": prompt},
            ],
            "max_tokens": 500,
            "temperature": 0.7,
        },
        timeout=timeout,
    )
    resp.raise_for_status()
    data = resp.json()
    return data["choices"][0]["message"]["content"].strip()


def run_macro_analysis(force_refresh: bool = False):
    api_key = _get_api_key()
    if not api_key:
        print("[Commander] DEEPSEEK_API_KEY not configured — falling back to technical signals")
        _run_technical_fallback()
        return

    print("Gathering market data for macro analysis...")
    try:
        session_data = analyze_all_sessions()
    except Exception as e:
        print(f"Failed to get session data: {e}")
        return

    # 获取之前的方向和分数
    try:
        bb = json.loads((ROOT / "blackboard_state.json").read_text())
        mc = bb.get("Macro_Commander", {})
        prev_dir = mc.get("bias", "")
        prev_score = float(mc.get("session_score", 0.0))
    except Exception:
        prev_dir = ""
        prev_score = None

    # =========================================================
    # 状态变化检测：如果 session score 变化极小，直接维持原方向
    # 宏观只做多：如果遗留方向为 SHORT，强制纠正为 LONG
    # =========================================================
    curr_score = session_data.get("overall_score", 0)
    if prev_dir and prev_score is not None and not force_refresh:
        if abs(curr_score - prev_score) < 0.5:
            if prev_dir == "SHORT":
                prev_dir = "LONG"
            print(f"[Commander] 状态无显著变化 (Score: {prev_score} -> {curr_score})，拦截 LLM 调用，维持 {prev_dir}")
            reason = f"State remained stable (score change < 0.5). Maintained previous direction."
            conf = mc.get("confidence", 0.5)

            try:
                from src.swarm.blackboard import global_blackboard
                if global_blackboard:
                    global_blackboard.update("Macro_Commander", "bias", prev_dir)
                    global_blackboard.update("Macro_Commander", "confidence", conf)
                    global_blackboard.update("Macro_Commander", "session_score", curr_score)
                    global_blackboard.update("Macro_Commander", "status", "DONE")
                    global_blackboard.update("Macro_Commander", "degraded", False)
                    global_blackboard.add_log("Macro_Commander", "BROADCAST",
                        f"✅ 维持宏观定调: {prev_dir}，置信度: {conf:.2f}。理由: {reason[:30]}...")
            except Exception as e:
                print(f"[Commander] Failed to update blackboard: {e}")

            save_agent_direction(prev_dir, f"[DeepSeek] {reason}", conf)
            return

    # 准备给大模型的 Prompt
    prompt = f"""
You are the Commander (Macro Strategic Agent) for a Gold (XAUUSD) algorithmic trading system.
Your job is to determine the macro trading direction for the current market phase based on multi-session technical resonance.

Session Data (EMA biases, RSI, Volatility, Direction):
{json.dumps(session_data.get('all_sessions', {}), indent=2)}

Overall Technical Score: {session_data.get('overall_score')} (Positive means BULLISH, Negative means BEARISH)
Overall Technical Direction: {session_data.get('overall_direction')}

IMPORTANT: You are a LONG-ONLY macro strategist. You may only output LONG or NEUTRAL — never SHORT.
Provide your strategic direction (LONG or NEUTRAL), a confidence score (0.0 to 1.0), and a concise reason.
Output exactly in JSON format:
{{
  "direction": "LONG",
  "confidence": 0.8,
  "reason": "..."
}}
"""

    print(f"Calling DeepSeek API for macro analysis...")
    try:
        output = _call_deepseek_api(prompt, api_key)

        decision = extract_json_block(output)

        if not decision or "direction" not in decision:
            raise ValueError(f"Failed to parse valid decision from LLM output. Raw: {output[:200]}")

        direction = decision.get("direction", "NEUTRAL").upper()
        confidence = float(decision.get("confidence", 0.5))
        reason = decision.get("reason", "Parsed from LLM output")

        # 规范化方向（宏观只做多：仅 LONG / NEUTRAL）
        if direction not in ["LONG", "NEUTRAL"]:
            direction = "LONG"

        print(f"Decision: {direction} (Conf: {confidence}) - {reason}")
        save_agent_direction(direction, f"[DeepSeek] {reason}", confidence)

    except Exception as e:
        print(f"Macro analysis failed: {e}")
        _run_technical_fallback(session_data)


def _run_technical_fallback(session_data: dict = None):
    """降级方案：使用 session_analyzer 纯技术面的统计结果"""
    if session_data is None:
        try:
            session_data = analyze_all_sessions()
        except Exception as e:
            print(f"[Commander] Fallback: cannot get session data: {e}")
            save_agent_direction("LONG", "[Fallback] Default LONG", 0.5)
            return

    fallback_dir = session_data.get('overall_direction', 'NEUTRAL')
    if fallback_dir in ["SLIGHTLY_BULLISH", "BULLISH"]:
        direction = "LONG"
    elif fallback_dir in ["SLIGHTLY_BEARISH", "BEARISH"]:
        direction = "NEUTRAL"
    else:
        direction = "LONG"

    print(f"Fallback to technical direction: {direction}")
    save_agent_direction(direction, "[Fallback] Technical Resonance", 0.6)


if __name__ == "__main__":
    run_macro_analysis()
