#!/usr/bin/env python3
"""
🐶 狗蛋 MT5 桥接脚本 - Windows 服务器版 v2
部署路径: Windows 桌面 mt5_bridge.py

前置条件:
  pip install MetaTrader5 requests
  MT5终端已安装并至少登录过一次账户

用法（二选一）:
  # 方式1: 使用终端当前登录的账户（最简单）
  python mt5_bridge.py

  # 方式2: 指定账户信息（支持多账户）
  编辑 mt5_config.json 后运行

首次运行会生成 mt5_config.json 配置文件。
"""

import json, sys, time, requests
from pathlib import Path
from datetime import datetime, timedelta
from collections import defaultdict, Counter

CONFIG_FILE = Path(__file__).parent / "mt5_config.json"
API_URL = "https://gold.niuniuba.com/api/mt-upload"

DEFAULT_CONFIG = {
    "mode": "terminal",  # terminal(当前登录账户) | accounts(配置文件账户)
    "accounts": [
        {
            "name": "示例账户",
            "login": 0,
            "password": "",     # 观察者密码
            "server": ""         # MT5服务器名
        }
    ],
    "days": 365  # 拉取多少天的交易记录
}

def fmt_time(t):
    if isinstance(t, (int, float)) and t > 0:
        return datetime.fromtimestamp(t).strftime('%Y.%m.%d %H:%M:%S')
    return str(t)

def safe_get(d, key, default=0):
    return d.get(key, default) if d else default

def pull_trades_terminal(days=365):
    """从当前已登录的MT5终端拉取交易记录"""
    import MetaTrader5 as mt5

    if not mt5.initialize():
        error = mt5.last_error()
        raise Exception(f"MT5初始化失败: {error}")

    info = mt5.account_info()
    if info is None:
        mt5.shutdown()
        raise Exception("MT5终端未登录任何账户")

    info = info._asdict()
    login = info.get('login')
    server = info.get('server')
    balance = info.get('balance')
    print(f"📊 账户: {login} @ {server} | 余额: ${balance}")

    end = datetime.now()
    start = end - timedelta(days=days)

    deals = mt5.history_deals_get(start, end)
    if deals is None or len(deals) == 0:
        mt5.shutdown()
        raise Exception(f"近{days}天无交易记录")

    # 按position_id分组: entry=0=开仓, entry=1=平仓(含盈亏)
    pos_deals = defaultdict(lambda: {'open': None, 'close': None})
    for deal in deals:
        d = deal._asdict()
        pid = d.get('position_id', 0)
        if pid == 0:
            continue
        if d.get('entry') == 0:
            pos_deals[pid]['open'] = d
        elif d.get('entry') == 1:
            pos_deals[pid]['close'] = d

    trades = []
    for pid, pd in pos_deals.items():
        close = pd['close']
        if not close:
            continue
        opn = pd['open']
        direction = 'buy' if safe_get(opn, 'type') == 0 else 'sell'
        trades.append({
            'ticket': pid,
            'open_time': fmt_time(safe_get(opn, 'time')),
            'type': direction,
            'size': round(safe_get(close, 'volume') or safe_get(opn, 'volume'), 2),
            'symbol': safe_get(close, 'symbol') or safe_get(opn, 'symbol'),
            'open_price': round(safe_get(opn, 'price'), 5),
            'sl': 0, 'tp': 0,
            'close_time': fmt_time(safe_get(close, 'time')),
            'close_price': round(safe_get(close, 'price'), 5),
            'commission': round(safe_get(close, 'commission'), 2),
            'swap': round(safe_get(close, 'swap'), 2),
            'profit': round(safe_get(close, 'profit'), 2),
        })

    mt5.shutdown()
    return trades, {'login': login, 'server': server}

def pull_trades_account(account, days=365):
    """使用账号密码连接MT5"""
    import MetaTrader5 as mt5

    login = int(account.get('login', 0))
    password = account.get('password', '')
    server = account.get('server', '')

    if not login or not server:
        raise Exception(f"缺少账号/服务器信息: {account}")

    if not mt5.initialize(login=login, password=password, server=server):
        error = mt5.last_error()
        mt5.shutdown()
        raise Exception(f"登录失败: {error}")

    info = mt5.account_info()._asdict()
    print(f"📊 账户: {info.get('login')} @ {info.get('server')} | 余额: ${info.get('balance')}")

    # Same deal parsing as terminal mode...
    end = datetime.now()
    start = end - timedelta(days=days)
    deals = mt5.history_deals_get(start, end)
    if deals is None or len(deals) == 0:
        mt5.shutdown()
        raise Exception("无交易记录")

    pos_deals = defaultdict(lambda: {'open': None, 'close': None})
    for deal in deals:
        d = deal._asdict()
        pid = d.get('position_id', 0)
        if pid == 0:
            continue
        if d.get('entry') == 0:
            pos_deals[pid]['open'] = d
        elif d.get('entry') == 1:
            pos_deals[pid]['close'] = d

    trades = []
    for pid, pd in pos_deals.items():
        close = pd['close']
        if not close:
            continue
        opn = pd['open']
        direction = 'buy' if safe_get(opn, 'type') == 0 else 'sell'
        trades.append({
            'ticket': pid,
            'open_time': fmt_time(safe_get(opn, 'time')),
            'type': direction,
            'size': round(safe_get(close, 'volume') or safe_get(opn, 'volume'), 2),
            'symbol': safe_get(close, 'symbol') or safe_get(opn, 'symbol'),
            'open_price': round(safe_get(opn, 'price'), 5),
            'sl': 0, 'tp': 0,
            'close_time': fmt_time(safe_get(close, 'time')),
            'close_price': round(safe_get(close, 'price'), 5),
            'commission': round(safe_get(close, 'commission'), 2),
            'swap': round(safe_get(close, 'swap'), 2),
            'profit': round(safe_get(close, 'profit'), 2),
        })

    mt5.shutdown()
    return trades, {'login': info.get('login'), 'server': info.get('server')}

def push_to_server(trades):
    """推送到分析网站"""
    # Convert ticket to string for JSON compatibility
    payload = [{**t, 'ticket': str(t['ticket'])} for t in trades]

    resp = requests.post(API_URL, json=payload, headers={'Content-Type': 'application/json'}, timeout=120)
    return resp.json()

def main():
    print("🐶 狗蛋 MT5 桥接 v2")
    print("=" * 50)

    # Load/create config
    config = DEFAULT_CONFIG.copy()
    if CONFIG_FILE.exists():
        with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
            config.update(json.load(f))
    else:
        with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
            json.dump(DEFAULT_CONFIG, f, indent=2, ensure_ascii=False)
        print("✅ 已创建 mt5_config.json，使用默认终端模式")

    days = config.get('days', 365)
    mode = config.get('mode', 'terminal')

    if mode == 'terminal':
        # 模式1: 使用已登录终端
        try:
            trades, acct = pull_trades_terminal(days)
            print(f"获取到 {len(trades)} 笔已平仓交易")

            wins = [t for t in trades if t['profit'] > 0]
            losses = [t for t in trades if t['profit'] < 0]
            print(f"胜: {len(wins)} 负: {len(losses)}")
            if wins:
                print(f"总盈利: ${sum(t['profit'] for t in wins):.2f}")
            if losses:
                print(f"总亏损: ${sum(t['profit'] for t in losses):.2f}")

            syms = Counter(t['symbol'] for t in trades)
            print(f"品种: {dict(syms.most_common(3))}")

            print("\n📤 推送到 gold.niuniuba.com...")
            result = push_to_server(trades)

            if result.get('error'):
                print(f"❌ {result['error']}")
            else:
                s = result.get('stats', {})
                k = result.get('keywords', {})
                print(f"\n✅ 推送成功！")
                print(f"评分: {k.get('score')}/100 | 胜率: {s.get('win_rate')}% | PF: {s.get('profit_factor')}")
                print(f"净利润: ${s.get('net_profit')} | 期望值: ${s.get('expectancy')}")

                ai = result.get('ai_analysis', '')
                if ai:
                    print(f"\n{'='*50}")
                    print("🤖 AI 诊断:")
                    print(ai)
        except Exception as e:
            print(f"❌ {e}")

    elif mode == 'accounts':
        # 模式2: 配置文件指定账户
        accounts = config.get('accounts', [])
        for acct in accounts:
            name = acct.get('name', f"账户{acct.get('login')}")
            print(f"\n📊 处理: {name}")
            try:
                trades, _ = pull_trades_account(acct, days)
                print(f"{len(trades)} 笔交易 → 推送中...")
                result = push_to_server(trades)
                if result.get('error'):
                    print(f"❌ {result['error']}")
                else:
                    s = result.get('stats', {})
                    k = result.get('keywords', {})
                    print(f"✅ 评分:{k.get('score')} | WR:{s.get('win_rate')}% | Net:${s.get('net_profit')}")
            except Exception as e:
                print(f"❌ {e}")

    print(f"\n查看分析: https://gold.niuniuba.com")

if __name__ == '__main__':
    main()
