#!/usr/bin/env python3
"""
交易通知器 - 带Inline Keyboard按钮的推送
用法:
  python3 trade_notifier.py notify '{"symbol":"BTC","side":"long","leverage":10,...}'
  python3 trade_notifier.py callback <callback_data>  # 处理按钮点击
"""

import os
import re
import sys
import json
import time
import requests

def _load_env():
    """Load TELEGRAM_BOT_TOKEN from ~/.hermes/.env"""
    env_path = os.path.expanduser("~/.hermes/.env")
    with open(env_path) as f:
        for line in f:
            m = re.match(r'TELEGRAM_BOT_TOKEN=(.*)', line.strip())
            if m:
                return m.group(1).strip()
    return ''

BOT_TOKEN = _load_env()
PROXY = 'http://127.0.0.1:7890'
PENDING_DIR = os.path.expanduser("~/.hermes/trading/pending")
CALLBACK_LOG = os.path.expanduser("~/.hermes/trading/callbacks.jsonl")

os.makedirs(PENDING_DIR, exist_ok=True)

def send_message_with_buttons(chat_id, text, buttons=None):
    """Send message, optionally with inline keyboard buttons"""
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
    payload = {
        "chat_id": chat_id,
        "text": text,
        "parse_mode": "Markdown",
    }
    if buttons:
        payload["reply_markup"] = json.dumps({"inline_keyboard": buttons})
    resp = requests.post(url, data=payload, proxies={"https": PROXY, "http": PROXY}, timeout=15)
    return resp.json()


def edit_message_buttons(chat_id, message_id, text, buttons=None):
    """Edit message text and optionally update buttons"""
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/editMessageText"
    payload = {
        "chat_id": chat_id,
        "message_id": message_id,
        "text": text,
        "parse_mode": "Markdown",
    }
    if buttons:
        payload["reply_markup"] = json.dumps({"inline_keyboard": buttons})
    resp = requests.post(url, data=payload, proxies={"https": PROXY, "http": PROXY}, timeout=15)
    return resp.json()


def answer_callback(callback_query_id, text=""):
    """Answer callback query to remove loading state"""
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/answerCallbackQuery"
    payload = {"callback_query_id": callback_query_id}
    if text:
        payload["text"] = text
    resp = requests.post(url, data=payload, proxies={"https": PROXY, "http": PROXY}, timeout=10)
    return resp.json()


def format_recommendation(rec):
    """Format recommendation for display"""
    symbol = rec.get("symbol", "?")
    side_cn = rec.get("side_cn", "做多" if rec.get("side") in ("long", "buy") else "做空")
    leverage = rec.get("leverage", 10)
    contracts = rec.get("contracts", 0)
    entry = rec.get("price", 0)
    tp = rec.get("tp_price", 0)
    sl = rec.get("sl_price", 0)
    margin = rec.get("margin", 0)
    margin_pct = rec.get("margin_pct", 0)
    tp_pct = rec.get("tp_pct", 0)  # 标的价格变动%
    sl_pct = rec.get("sl_pct", 0)
    tp_pnl = rec.get("tp_pnl", 0)
    sl_pnl = rec.get("sl_pnl", 0)
    rr = rec.get("rr", 0)
    liq_price = rec.get("liq_price", 0)
    liq_pct = rec.get("liq_pct", 0)
    balance = rec.get("acct_free", 0)
    # 保证金收益率
    tp_margin_pct = (tp_pnl / margin * 100) if margin > 0 else 0
    sl_margin_pct = (sl_pnl / margin * 100) if margin > 0 else 0

    lines = [
        f"📊 *{symbol} {side_cn}* — 仓位推荐",
        "",
        f"💰 可用余额: {balance:.2f} USDT",
        f"📈 当前价: *{entry}*",
        "",
        "*开仓方案:*",
        f"• 方向: {side_cn}",
        f"• 杠杆: *{leverage}x*",
        f"• 张数: *{contracts}张*",
        f"• 保证金: {margin:.2f} USDT ({margin_pct:.0f}%)",
        "",
        "*止盈止损:*",
        f"• 🎯 止盈: *{tp}* (保证金+{tp_margin_pct:.0f}%) → +{tp_pnl:.2f} USDT",
        f"• 🛑 止损: *{sl}* (保证金-{sl_margin_pct:.0f}%) → -{sl_pnl:.2f} USDT",
        f"• 📐 盈亏比: *{rr}:1*",
    ]

    if liq_price:
        lines.append(f"• ⚠️ 清算价: {liq_price} (距离 {liq_pct}%)")

    return "\n".join(lines)


def notify(chat_id, rec_json):
    """Send trade recommendation (text only, no buttons to avoid polling conflict)"""
    rec = json.loads(rec_json) if isinstance(rec_json, str) else rec_json
    symbol = rec.get("symbol", "").split("/")[0].replace("USDT", "")
    side = rec.get("side", "long")
    
    # Save pending
    pending_path = os.path.join(PENDING_DIR, f"{symbol}.json")
    with open(pending_path, "w") as f:
        json.dump({"symbol": symbol, "side": side, "rec": rec, "timestamp": time.time()}, f)
    
    text = format_recommendation(rec)
    # No buttons - use text Y/N reply instead (avoids getUpdates conflict with gateway)
    result = send_message_with_buttons(chat_id, text, None)
    return result


def handle_callback(callback_data, chat_id, message_id, callback_query_id):
    """Handle button click"""
    action, symbol = callback_data.split(":", 1)
    
    # Log callback
    with open(CALLBACK_LOG, "a") as f:
        f.write(json.dumps({"action": action, "symbol": symbol, "time": time.time(), "chat_id": chat_id}) + "\n")
    
    if action == "trade_confirm":
        # Load pending
        pending_path = os.path.join(PENDING_DIR, f"{symbol}.json")
        if not os.path.exists(pending_path):
            answer_callback(callback_query_id, "❌ 未找到待确认交易")
            return {"error": "no pending"}
        
        with open(pending_path) as f:
            pending = json.load(f)
        
        rec = pending["rec"]
        
        # Execute trade
        import subprocess
        script_dir = os.path.dirname(os.path.abspath(__file__))
        advisor = os.path.join(script_dir, "okx_position_advisor.py")
        rec_str = json.dumps(rec, ensure_ascii=False)
        
        cmd = ["bash", "-c", f"source ~/.bashrc && python3 {advisor} --symbol {symbol} --side {rec.get('side','long')} --execute --json --rec-json '{rec_str}'"]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
        
        # Remove pending
        os.remove(pending_path)
        
        if result.returncode != 0:
            answer_callback(callback_query_id, "❌ 下单失败")
            edit_message_buttons(chat_id, message_id, f"❌ *{symbol} 下单失败*\n\n{result.stderr[:200]}")
            return {"error": result.stderr}
        
        try:
            exec_result = json.loads(result.stdout)
        except:
            exec_result = {"raw": result.stdout}
        
        # Format result
        side_cn = "做多" if rec.get("side") in ("long", "buy") else "做空"
        result_text = f"✅ *{symbol} {side_cn} 开仓成功*\n\n"
        
        for step in exec_result.get("steps", []):
            if step.get("status") == "ok":
                if step["step"] == "leverage":
                    result_text += "✅ 杠杆设置成功\n"
                elif step["step"] == "order":
                    result_text += f"✅ 下单成功 (ID: {step.get('order_id', '?')})\n"
                elif step["step"] == "tp_sl":
                    result_text += f"✅ 止盈止损设置成功\n"
        
        pos = exec_result.get("position")
        if pos:
            pnl_emoji = "🟢" if pos.get("pnl", 0) >= 0 else "🔴"
            result_text += f"\n📊 *持仓确认:*\n"
            result_text += f"• 数量: {pos.get('contracts', '?')}张\n"
            result_text += f"• 入场价: *{pos.get('entry', '?')}*\n"
            result_text += f"• {pnl_emoji} 浮盈: {pos.get('pnl', 0):.2f} USDT\n"
        
        algo = exec_result.get("algo")
        if algo:
            result_text += f"\n🎯 止盈: *{algo.get('tp', '?')}*\n"
            result_text += f"🛑 止损: *{algo.get('sl', '?')}*\n"
        
        answer_callback(callback_query_id, "✅ 已下单")
        edit_message_buttons(chat_id, message_id, result_text)
        return exec_result
    
    elif action == "trade_cancel":
        # Remove pending
        pending_path = os.path.join(PENDING_DIR, f"{symbol}.json")
        if os.path.exists(pending_path):
            os.remove(pending_path)
        
        answer_callback(callback_query_id, "❌ 已取消")
        edit_message_buttons(chat_id, message_id, f"❌ *{symbol} 交易已取消*")
        return {"cancelled": True}


def main():
    if len(sys.argv) < 2:
        print("用法: trade_notifier.py notify|callback [args]")
        sys.exit(1)
    
    action = sys.argv[1]
    
    if action == "notify":
        if len(sys.argv) < 4:
            print("用法: trade_notifier.py notify <chat_id> <rec_json>")
            sys.exit(1)
        chat_id = sys.argv[2]
        rec_json = sys.argv[3]
        result = notify(chat_id, rec_json)
        print(json.dumps(result, ensure_ascii=False))
    
    elif action == "callback":
        if len(sys.argv) < 6:
            print("用法: trade_notifier.py callback <callback_data> <chat_id> <message_id> <callback_query_id>")
            sys.exit(1)
        callback_data = sys.argv[2]
        chat_id = sys.argv[3]
        message_id = sys.argv[4]
        callback_query_id = sys.argv[5]
        result = handle_callback(callback_data, chat_id, message_id, callback_query_id)
        print(json.dumps(result, ensure_ascii=False, default=str))
    
    else:
        print(f"Unknown action: {action}")
        sys.exit(1)


if __name__ == "__main__":
    main()
