#!/usr/bin/env python3
"""
交易信号处理器 - 一体化脚本
用法:
  python3 trade_signal_handler.py signal "【币种】BTCUSDT|永续|10x\n【方向】做多\n【仓位】0.5 BTC"
  python3 trade_signal_handler.py confirm BTC
  python3 trade_signal_handler.py cancel BTC
  python3 trade_signal_handler.py status
"""

import re
import os
import sys
import json
import time
import glob
import subprocess

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ADVISOR_SCRIPT = os.path.join(SCRIPT_DIR, "okx_position_advisor.py")
SIGNAL_DB_SCRIPT = os.path.join(SCRIPT_DIR, "signal_db.py")
PENDING_DIR = os.path.expanduser("~/.hermes/trading/pending")

os.makedirs(PENDING_DIR, exist_ok=True)


def log_signal_to_db(signal_text):
    """Log signal to history database, return signal_id or None"""
    try:
        result = subprocess.run(
            [sys.executable, SIGNAL_DB_SCRIPT, "log", signal_text],
            capture_output=True, text=True, timeout=10,
        )
        if result.returncode == 0:
            return json.loads(result.stdout).get("id")
    except Exception:
        pass
    return None


def update_signal_outcome(signal_id, outcome, detail=""):
    """Update signal outcome in database"""
    if not signal_id:
        return
    try:
        subprocess.run(
            [sys.executable, SIGNAL_DB_SCRIPT, "update", str(signal_id), outcome, detail],
            capture_output=True, text=True, timeout=10,
        )
    except Exception:
        pass


def parse_signal(text):
    """Parse trading signal text, extract symbol/direction/leverage/size"""
    result = {}

    # 币种: BTCUSDT|永续|10x or 【币种】BTCUSDT
    symbol_match = re.search(r'(?:【币种】|币种[：:]\s*)(\w+)', text)
    if not symbol_match:
        symbol_match = re.search(r'([A-Z]{2,10})USDT', text)
    if symbol_match:
        raw = symbol_match.group(1).upper()
        raw = raw.replace("USDT", "").replace("/USDT", "").replace(":USDT", "")
        result["symbol"] = raw
    else:
        return None

    # 方向
    if re.search(r'(做空|卖出|short|sell|空单|开空)', text, re.IGNORECASE):
        result["side"] = "short"
    elif re.search(r'(做多|买入|long|buy|多单|开多)', text, re.IGNORECASE):
        result["side"] = "long"
    else:
        return None

    # 杠杆
    lev_match = re.search(r'(\d+)\s*[xX倍]', text)
    result["leverage"] = int(lev_match.group(1)) if lev_match else 10

    # 仓位数量
    size_match = re.search(r'(?:【仓位】|仓位[：:]\s*)([\d,.]+)\s*(\w+)', text)
    if size_match:
        result["raw_size"] = float(size_match.group(1).replace(",", ""))
        result["raw_unit"] = size_match.group(2)

    # 是否加仓/平仓
    result["is_add"] = bool(re.search(r'(加仓|追仓)', text))
    result["is_close"] = bool(re.search(r'(平仓|止盈|止损|close|全平)', text, re.IGNORECASE))

    return result


def save_pending(symbol, rec_json, signal_text, signal_id=None):
    """Save pending recommendation to file"""
    path = os.path.join(PENDING_DIR, f"{symbol.upper()}.json")
    data = {
        "symbol": symbol.upper(),
        "rec": rec_json,
        "signal": signal_text,
        "signal_id": signal_id,
        "timestamp": time.time(),
        "time_str": time.strftime("%Y-%m-%d %H:%M:%S"),
    }
    with open(path, "w") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    return path


def load_pending(symbol):
    """Load pending recommendation"""
    path = os.path.join(PENDING_DIR, f"{symbol.upper()}.json")
    if not os.path.exists(path):
        return None
    with open(path) as f:
        return json.load(f)


def remove_pending(symbol):
    """Remove pending recommendation"""
    path = os.path.join(PENDING_DIR, f"{symbol.upper()}.json")
    if os.path.exists(path):
        os.remove(path)


def run_advisor(symbol, side, leverage):
    """Run the advisor script and return JSON result"""
    cmd = [
        sys.executable, ADVISOR_SCRIPT,
        "--symbol", symbol,
        "--side", side,
        "--leverage", str(leverage),
        "--json",
    ]
    env = os.environ.copy()
    # Source bashrc to get OKX credentials
    result = subprocess.run(
        ["bash", "-c", f"source ~/.bashrc && {' '.join(cmd)}"],
        capture_output=True, text=True, timeout=30,
    )
    if result.returncode != 0:
        return {"error": result.stderr.strip() or "Advisor script failed"}
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        return {"error": f"Invalid JSON output: {result.stdout[:200]}"}


def execute_trade(rec_json):
    """Execute the trade using the advisor script"""
    import shlex
    rec_str = json.dumps(rec_json, ensure_ascii=False)
    symbol = rec_json.get("symbol", "").split("/")[0]
    side = rec_json.get("side", "")
    cmd = f"source ~/.bashrc && python3 {ADVISOR_SCRIPT} --symbol {symbol} --side {side} --execute --json --rec-json {shlex.quote(rec_str)}"
    result = subprocess.run(
        ["bash", "-c", cmd],
        capture_output=True, text=True, timeout=60,
    )
    if result.returncode != 0:
        return {"error": result.stderr.strip() or "Execution failed"}
    try:
        return json.loads(result.stdout)
    except json.JSONDecodeError:
        return {"raw": result.stdout.strip()}


def format_recommendation(rec, signal_text=""):
    """Format recommendation for user display"""
    symbol = rec.get("symbol", "?")
    side = rec.get("side", "?")
    side_cn = "做多" if side in ("long", "buy") else "做空"
    leverage = rec.get("leverage", 10)
    contracts = rec.get("contracts", 0)
    entry = rec.get("entry_price", 0)
    tp = rec.get("tp_price", 0)
    sl = rec.get("sl_price", 0)
    margin = rec.get("margin_used", 0)
    balance = rec.get("balance", 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)
    # 保证金收益率
    tp_margin_pct = (tp_pnl / margin * 100) if margin > 0 else 0
    sl_margin_pct = (sl_pnl / margin * 100) if margin > 0 else 0
    liq_price = rec.get("liq_price", 0)
    liq_pct = rec.get("liq_pct", 0)
    rr = rec.get("rr_ratio", 0)

    lines = [
        f"📊 **{symbol}USDT {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:.1f}:1**",
    ]

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

    lines.extend([
        "",
        "回复 **Y** 确认下单",
        "回复 **N** 取消",
    ])

    return "\n".join(lines)


def format_execution_result(result, symbol, side):
    """Format execution result for user display"""
    if "error" in result:
        return f"❌ **{symbol}USDT 下单失败**\n\n{result['error']}"

    side_cn = "做多" if side in ("long", "buy") else "做空"
    lines = [f"✅ **{symbol}USDT {side_cn} 开仓成功**"]

    # Parse steps
    for step in result.get('steps', []):
        if step['step'] == 'leverage':
            if step['status'] == 'ok':
                lines.append("✅ 杠杆设置成功")
            else:
                lines.append(f"⚠️ 杠杆: {step.get('msg', '')}")
        elif step['step'] == 'order':
            if step['status'] == 'ok':
                lines.append(f"✅ 下单成功 (ID: {step['order_id']})")
            else:
                lines.append(f"❌ 下单失败: {step.get('msg', '')}")
                return '\n'.join(lines)
        elif step['step'] == 'tp_sl':
            if step['status'] == 'ok':
                lines.append(f"✅ 止盈止损设置成功 (ID: {step['algo_id']})")
            else:
                lines.append(f"⚠️ 止盈止损: {step.get('msg', '')}")

    # Position info
    pos = result.get('position')
    if pos:
        pnl_emoji = "🟢" if pos.get('pnl', 0) >= 0 else "🔴"
        lines.extend([
            "",
            "📊 **持仓确认:**",
            f"• 方向: {side_cn}",
            f"• 数量: {pos.get('contracts', '?')}张",
            f"• 入场价: **{pos.get('entry', '?')}**",
            f"• {pnl_emoji} 浮盈: {pos.get('pnl', 0):.2f} USDT",
        ])

    # TP/SL info
    algo = result.get('algo')
    if algo:
        lines.extend([
            "",
            "🎯 **止盈止损:**",
            f"• 止盈: **{algo.get('tp', '?')}**",
            f"• 止损: **{algo.get('sl', '?')}**",
        ])

    return "\n".join(lines)


def main():
    if len(sys.argv) < 2:
        print("用法: trade_signal_handler.py <signal|confirm|cancel|status> [args]")
        sys.exit(1)

    action = sys.argv[1]

    if action == "signal":
        if len(sys.argv) < 3:
            print("用法: trade_signal_handler.py signal '<signal_text>'")
            sys.exit(1)
        signal_text = sys.argv[2]
        parsed = parse_signal(signal_text)
        if not parsed:
            print(json.dumps({"error": "无法解析信号", "raw": signal_text}))
            sys.exit(1)

        if parsed.get("is_close"):
            # 平仓信号
            print(json.dumps({"action": "close", "symbol": parsed["symbol"]}))
            sys.exit(0)

        # 记录信号到数据库
        signal_id = log_signal_to_db(signal_text)

        # 计算仓位
        rec = run_advisor(parsed["symbol"], parsed["side"], parsed["leverage"])
        if "error" in rec:
            if signal_id:
                update_signal_outcome(signal_id, "error", rec["error"])
            print(json.dumps(rec))
            sys.exit(1)

        # 保存待确认
        save_pending(parsed["symbol"], rec, signal_text, signal_id)

        # 输出推荐
        output = {
            "action": "recommend",
            "symbol": parsed["symbol"],
            "side": parsed["side"],
            "recommendation": rec,
            "display": format_recommendation(rec, signal_text),
        }
        print(json.dumps(output, ensure_ascii=False))

    elif action == "confirm":
        if len(sys.argv) < 3:
            print("用法: trade_signal_handler.py confirm <SYMBOL>")
            sys.exit(1)
        symbol = sys.argv[2].upper().replace("USDT", "")
        pending = load_pending(symbol)
        if not pending:
            print(json.dumps({"error": f"没有待确认的 {symbol} 交易"}))
            sys.exit(1)

        rec = pending["rec"]
        signal_id = pending.get("signal_id")
        result = execute_trade(rec)
        
        # Only remove pending if execution succeeded
        if not result.get("error"):
            remove_pending(symbol)
            if signal_id:
                update_signal_outcome(signal_id, "confirmed", json.dumps(result, ensure_ascii=False)[:500])
        else:
            if signal_id:
                update_signal_outcome(signal_id, "error", result.get("error", "")[:200])
        
        output = {
            "action": "executed",
            "symbol": symbol,
            "side": rec.get("side"),
            "result": result,
            "display": format_execution_result(result, symbol, rec.get("side")),
        }
        print(json.dumps(output, ensure_ascii=False))

    elif action == "cancel":
        if len(sys.argv) < 3:
            print("用法: trade_signal_handler.py cancel <SYMBOL>")
            sys.exit(1)
        symbol = sys.argv[2].upper().replace("USDT", "")
        pending = load_pending(symbol)
        signal_id = pending.get("signal_id") if pending else None
        remove_pending(symbol)
        if signal_id:
            update_signal_outcome(signal_id, "cancelled")
        print(json.dumps({"action": "cancelled", "symbol": symbol}))

    elif action == "status":
        pending_files = glob.glob(os.path.join(PENDING_DIR, "*.json"))
        if not pending_files:
            print(json.dumps({"pending": []}))
        else:
            pending = []
            for f in pending_files:
                with open(f) as fh:
                    d = json.load(fh)
                    pending.append({
                        "symbol": d["symbol"],
                        "side": d["rec"].get("side"),
                        "time": d.get("time_str", d.get("timestamp", "unknown")),
                    })
            print(json.dumps({"pending": pending}, ensure_ascii=False))

    elif action == "history":
        # Forward to signal_db.py
        result = subprocess.run(
            [sys.executable, SIGNAL_DB_SCRIPT, "history"] + sys.argv[2:],
            capture_output=True, text=True, timeout=10,
        )
        print(result.stdout)
        if result.returncode != 0 and result.stderr:
            print(result.stderr, file=sys.stderr)

    elif action == "stats":
        result = subprocess.run(
            [sys.executable, SIGNAL_DB_SCRIPT, "stats"],
            capture_output=True, text=True, timeout=10,
        )
        print(result.stdout)

    elif action == "traders":
        result = subprocess.run(
            [sys.executable, SIGNAL_DB_SCRIPT, "traders"],
            capture_output=True, text=True, timeout=10,
        )
        print(result.stdout)

    else:
        print(f"Unknown action: {action}")
        sys.exit(1)


if __name__ == "__main__":
    main()
