#!/usr/bin/env python3
"""
交易信号处理器（no_agent模式）：
1. 解析TG信号文本
2. 调advisor脚本获取正确金额
3. 格式化含📐完整模板
4. 推QQ
5. 信号去重/合并

用法: python3 process_signal.py "信号文本"
或: echo "信号文本" | python3 process_signal.py

cron模式: 作为no_agent cron job的script使用
"""
import sys
import re
import json
import subprocess
import sqlite3
import hashlib
from pathlib import Path
from datetime import datetime, timedelta

SKILL_DIR = Path.home() / ".hermes/skills/trading/okx-auto-position"
ADVISOR = SKILL_DIR / "scripts" / "okx_position_advisor.py"
QQ_PUSH = Path.home() / ".hermes/scripts/push_to_qq.sh"
SIGNAL_DB = Path.home() / ".hermes/trading/signal_history.db"
DEDUP_DB = Path.home() / ".hermes/trading/signal_dedup.db"

# Import signal tracker
sys.path.insert(0, str(SKILL_DIR / "scripts"))
from signal_tracker import format_comparison, record_signal as _tracker_record, record_confirmed, format_trader_rating

# ─── 解析 ────────────────────────────────────────────────────────────────

def parse_signal(text):
    """从TG信号文本提取关键字段"""
    fields = {}

    # 交易员
    m = re.search(r'【([^】]{1,20})】', text)
    if m:
        fields['trader'] = m.group(1)

    # 字段映射
    extractors = {
        'symbol':  r'【币种】\s*[:：]?\s*(\S+)',
        'side':    r'【方向】\s*[:：]?\s*(做多|做空)',
        'leverage':r'【杠杆】\s*[:：]?\s*(\d+)',
        'size':    r'【仓位大小】\s*[:：]?\s*([\d,.]+)',
        'value':   r'【仓位价值】\s*[:：]?\s*\$?\s*([\d,.]+)',
        'entry':   r'【开仓价】\s*[:：]?\s*([\d,.]+)',
        'current': r'【当前价】\s*[:：]?\s*([\d,.]+)',
        'pnl':     r'【未实现盈亏】\s*[:：]?\s*([-\d,.]+)',
        'margin':  r'【保证金】\s*[:：]?\s*\$?\s*([\d,.]+)',
    }

    for key, pattern in extractors.items():
        m = re.search(pattern, text)
        if m:
            fields[key] = m.group(1).replace(',', '')

    # 清理symbol
    if 'symbol' in fields:
        sym = fields['symbol']
        sym = re.sub(r'\|.*$', '', sym)  # 去掉 |永续|10x
        sym = sym.replace('USDT', '').strip()
        fields['symbol'] = sym

    # 方向转英文
    if fields.get('side', '').startswith('做多'):
        fields['side_en'] = 'long'
    else:
        fields['side_en'] = 'short'

    return fields

# ─── 去重 ────────────────────────────────────────────────────────────────

def init_dedup_db():
    conn = sqlite3.connect(str(DEDUP_DB))
    conn.execute("""
        CREATE TABLE IF NOT EXISTS recent_signals (
            id TEXT PRIMARY KEY,
            symbol TEXT,
            trader TEXT,
            timestamp REAL,
            raw_text TEXT
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS processed (
            msg_hash TEXT PRIMARY KEY,
            processed_at REAL
        )
    """)
    conn.commit()
    return conn

def is_duplicate(conn, text, symbol, trader):
    """检查是否重复信号（同交易员同币种2分钟内）"""
    msg_hash = hashlib.md5(text.encode()).hexdigest()

    # 检查完全相同的消息
    row = conn.execute(
        "SELECT 1 FROM processed WHERE msg_hash = ?", (msg_hash,)
    ).fetchone()
    if row:
        return True

    # 检查同交易员同币种2分钟内的信号
    cutoff = datetime.now().timestamp() - 120  # 2分钟
    row = conn.execute(
        """SELECT 1 FROM recent_signals
           WHERE symbol = ? AND trader = ? AND timestamp > ?
           ORDER BY timestamp DESC LIMIT 1""",
        (symbol, trader, cutoff)
    ).fetchone()

    return row is not None

def record_signal(conn, text, symbol, trader):
    """记录信号用于去重"""
    msg_hash = hashlib.md5(text.encode()).hexdigest()
    now = datetime.now().timestamp()

    conn.execute(
        "INSERT OR REPLACE INTO processed (msg_hash, processed_at) VALUES (?, ?)",
        (msg_hash, now)
    )
    conn.execute(
        "INSERT OR REPLACE INTO recent_signals (id, symbol, trader, timestamp, raw_text) VALUES (?, ?, ?, ?, ?)",
        (msg_hash, symbol, trader, now, text[:500])
    )

    # 清理1小时前的记录
    cutoff = now - 3600
    conn.execute("DELETE FROM recent_signals WHERE timestamp < ?", (cutoff,))
    conn.execute("DELETE FROM processed WHERE processed_at < ?", (cutoff,))
    conn.commit()

# ─── Advisor ──────────────────────────────────────────────────────────────

def run_advisor(symbol, side, leverage):
    """调advisor脚本获取正确数据"""
    cmd = [
        'python3', str(ADVISOR),
        '--symbol', symbol,
        '--side', side,
        '--leverage', str(leverage),
        '--json'
    ]

    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=30,
            cwd=str(ADVISOR.parent)
        )
        if result.returncode == 0:
            return json.loads(result.stdout)
        else:
            return {'error': result.stderr.strip()[:200]}
    except subprocess.TimeoutExpired:
        return {'error': 'advisor超时'}
    except json.JSONDecodeError:
        return {'error': 'advisor输出非JSON'}
    except Exception as e:
        return {'error': str(e)}

# ─── 分类 ────────────────────────────────────────────────────────────────

def classify_signal(fields):
    """判断信号类型：加仓/新开仓/减仓/平仓"""
    text = fields.get('_raw', '')

    # 平仓信号
    if '平仓' in text or '止盈' in text or '止损' in text:
        return 'close'

    # 减仓信号
    pnl = float(fields.get('pnl', '0').replace('+', ''))
    if '减仓' in text or (pnl < 0 and '减' in text):
        return 'reduce'

    # 默认为新开仓或加仓（由advisor判断）
    return 'open'

# ─── 格式化 ──────────────────────────────────────────────────────────────

def format_message(fields, rec, signal_type):
    """格式化完整推送消息"""
    if 'error' in rec:
        return f"⚠️ advisor错误: {rec['error']}"

    symbol = fields.get('symbol', '?')
    side_cn = fields.get('side', '做多')
    emoji = '🟩' if fields.get('side_en') == 'long' else '🟥'
    leverage = fields.get('leverage', '10')
    trader = fields.get('trader', '?')
    size = fields.get('size', '?')
    value = fields.get('value', '?')
    entry_price = fields.get('entry', '?')
    pnl_str = fields.get('pnl', '0')
    pnl = float(pnl_str.replace('+', '')) if pnl_str else 0
    current = rec.get('price', fields.get('current', '?'))

    pnl_emoji = '🔥' if pnl > 0 else '🔴'
    pnl_sign = '+' if pnl > 0 else ''

    # 性价比
    cc = rec.get('cost_check', {})
    rr = cc.get('rr_ratio', rec.get('rr', 0))
    profit = cc.get('profit_amount', rec.get('tp_pnl', 0))
    fee = cc.get('fee_cost', 0)
    fee_pct = cc.get('fee_pct', 0)
    net = cc.get('net_profit', 0)
    rating_emoji = cc.get('rating_emoji', '⚠️')
    rating_text = cc.get('rating_text', '未知')

    # 信号类型标签
    type_labels = {
        'open': '新开仓' if not fields.get('_is_add') else 'A类加仓',
        'reduce': 'B类减仓',
        'close': '平仓',
    }
    type_label = type_labels.get(signal_type, signal_type)

    # 信号源仓位（只展示，不参与计算）
    src_info = f"📊 {trader} {size} {symbol}（价值${value}）← 信号源，非你的仓位"

    # 仓位变化对比
    try:
        current_size = float(fields.get('size', '0').replace(',', ''))
        comparison = format_comparison(trader, symbol, current_size)
    except:
        comparison = ""

    # 交易员评分
    try:
        trader_rating = format_trader_rating(trader)
    except:
        trader_rating = ""

    msg = f"""⚡ 跟单建议 | {symbol} {side_cn} {emoji} {leverage}x（{type_label}）

{src_info}
入场: ${entry_price} | 当前: ${current}
浮盈: {pnl_sign}{pnl:.0f} {pnl_emoji}

📊 仓位变化
{comparison}

{trader_rating}

📐 性价比检查（基于你的推荐仓位）
• 你的仓位: {rec['contracts']}张（保证金{rec['margin']:.2f} USDT）
• 盈亏比: {rr}:1 {'✅' if rr >= 2 else '⚠️' if rr >= 1.5 else '❌'}
• 盈利额: +{profit:.2f} USDT {'✅' if profit >= 10 else '❌ <10U保底'}
• 手续费: {fee:.2f} USDT ({fee_pct:.1f}%) {'✅' if fee_pct < 5 else '❌'}
• 净盈利: {net:.2f} USDT {'✅' if net >= 10 else '❌'}
• 评级: {rating_emoji} {rating_text}
• SL: ${rec['sl_price']}（-{rec['sl_pct']:.1f}%）
• TP: ${rec['tp_price']}（+{rec['tp_pct']:.1f}%）

回复 Y 确认跟单 / N 取消"""

    # 如果余额不足，替换跟单方案
    if rec.get('contracts', 0) == 0:
        msg = f"""⚡ 跟单建议 | {symbol} {side_cn} {emoji} {leverage}x（{type_label}）

{src_info}
入场: ${entry_price} | 当前: ${current}
浮盈: {pnl_sign}{pnl:.0f} {pnl_emoji}

⚠️ 余额不足，无法开仓
• 可用: {rec.get('acct_free', 0):.2f} USDT
• 需要: ~{rec.get('margin', 0):.2f} USDT

💡 建议：等待其他仓位止盈释放保证金"""

    return msg

# ─── 推送 ────────────────────────────────────────────────────────────────

def push_to_qq(message):
    """推送到QQ"""
    try:
        result = subprocess.run(
            ['bash', str(QQ_PUSH), message],
            capture_output=True, text=True, timeout=15
        )
        return result.returncode == 0
    except:
        return False

# ─── 执行订单 ────────────────────────────────────────────────────────────

def execute_order(symbol, side, leverage, rec):
    """执行开仓订单"""
    cmd = [
        'python3', str(ADVISOR),
        '--symbol', symbol,
        '--side', side,
        '--leverage', str(leverage),
        '--execute', '--json',
        '--rec-json', json.dumps(rec)
    ]

    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=30,
            cwd=str(ADVISOR.parent)
        )
        if result.returncode == 0:
            return json.loads(result.stdout)
        else:
            return {'error': result.stderr.strip()[:200]}
    except Exception as e:
        return {'error': str(e)}

def format_execution_result(fields, rec, exec_result):
    """格式化执行结果"""
    symbol = fields.get('symbol', '?')
    side_cn = fields.get('side', '做多')
    emoji = '🟩' if fields.get('side_en') == 'long' else '🟥'
    leverage = fields.get('leverage', '10')
    trader = fields.get('trader', '?')
    size = fields.get('size', '?')
    value = fields.get('value', '?')

    cc = rec.get('cost_check', {})
    rr = cc.get('rr_ratio', rec.get('rr', 0))
    profit = cc.get('profit_amount', rec.get('tp_pnl', 0))
    fee = cc.get('fee_cost', 0)
    fee_pct = cc.get('fee_pct', 0)
    net = cc.get('net_profit', 0)
    rating_emoji = cc.get('rating_emoji', '⚠️')
    rating_text = cc.get('rating_text', '未知')

    pos = exec_result.get('position', {})
    algo = exec_result.get('algo', {})

    msg = f"""✅ {symbol} {side_cn} {emoji} {leverage}x 自动开仓

📊 信号源: {trader} {size} {symbol}（价值${value}）

📐 性价比检查
• 盈亏比: {rr}:1 ✅
• 盈利额: +{profit:.2f} USDT ✅
• 手续费: {fee:.2f} USDT ({fee_pct:.1f}%) ✅
• 净盈利: {net:.2f} USDT ✅
• 评级: {rating_emoji} {rating_text}

✅ 执行结果
• 入场: ${pos.get('entry', rec.get('price', '?'))}
• 仓位: {pos.get('contracts', rec.get('contracts', '?'))}张
• TP: ${algo.get('tp', rec.get('tp_price', '?'))}
• SL: ${algo.get('sl', rec.get('sl_price', '?'))}
• 强平: ${pos.get('liq', '?')}

━━━ 当前全部持仓 ━━━
（查询中...）"""

    # 尝试获取当前全部持仓
    try:
        acct_cmd = ['python3', '-c', f'''
import sys
sys.path.insert(0, "{ADVISOR.parent}")
from okx_position_advisor import load_credentials, create_exchange, get_account_info
creds = load_credentials()
exchange = create_exchange(creds)
info = get_account_info(exchange)
print(f"Free: {{info['usdt_free']:.2f}}")
for p in info['positions']:
    print(f"  {{p['symbol']}}: {{p['contracts']}}张 UPL={{p['pnl']:.2f}}")
''']
        acct_result = subprocess.run(acct_cmd, capture_output=True, text=True, timeout=15)
        if acct_result.returncode == 0:
            msg = msg.replace("（查询中...）", f"\n```\n{acct_result.stdout.strip()}\n```")
    except:
        pass

    return msg

# ─── 主流程 ──────────────────────────────────────────────────────────────

def process_signal(text):
    """处理一条信号"""
    # 解析
    fields = parse_signal(text)
    fields['_raw'] = text

    if not fields.get('symbol') or not fields.get('side'):
        return "⚠️ 无法解析信号"

    symbol = fields['symbol']
    side = fields['side_en']
    leverage = fields.get('leverage', '10')
    trader = fields.get('trader', '未知')

    # 去重
    dedup_conn = init_dedup_db()
    if is_duplicate(dedup_conn, text, symbol, trader):
        dedup_conn.close()
        return "⏭️ 重复信号，跳过"

    # 分类
    signal_type = classify_signal(fields)

    # 平仓信号直接推送
    if signal_type == 'close':
        msg = f"""🔔 {trader} {symbol}平仓提醒
{text[text.find("入场"):text.find("回复")].strip() if "入场" in text else "详情见原始信号"}

💡 操作建议
• 若已跟单{symbol}，建议同步止盈/止损"""
        record_signal(dedup_conn, text, symbol, trader)
        dedup_conn.close()
        push_to_qq(msg)
        return "✅ 平仓信号已推送"

    # 调advisor
    rec = run_advisor(symbol, side, leverage)

    if 'error' in rec:
        record_signal(dedup_conn, text, symbol, trader)
        dedup_conn.close()
        return f"⚠️ advisor错误: {rec['error']}"

    # 性价比检查
    cc = rec.get('cost_check', {})
    rr = cc.get('rr_ratio', rec.get('rr', 0))
    profit = cc.get('profit_amount', rec.get('tp_pnl', 0))
    fee_pct = cc.get('fee_pct', 0)
    auto_execute = cc.get('auto_execute', False) or (rr >= 2 and fee_pct < 5 and profit >= 10)

    if auto_execute and signal_type == 'open':
        # 性价比高 + 新开仓 → 自动执行
        exec_result = execute_order(symbol, side, leverage, rec)
        if exec_result and 'error' not in exec_result:
            msg = format_execution_result(fields, rec, exec_result)
            _tracker_record(trader=trader, symbol=symbol, side=side,
                          leverage=int(leverage) if leverage else 10,
                          trader_size=float(fields.get('size', '0').replace(',', '')),
                          trader_entry=float(fields.get('entry', '0').replace(',', '')),
                          trader_pnl=float(fields.get('pnl', '0').replace(',', '')),
                          raw_text=text, outcome='auto_executed')
        else:
            # 执行失败，降级为确认模式
            auto_execute = False
            msg = format_message(fields, rec, signal_type)
            _tracker_record(trader=trader, symbol=symbol, side=side,
                          leverage=int(leverage) if leverage else 10,
                          trader_size=float(fields.get('size', '0').replace(',', '')),
                          trader_entry=float(fields.get('entry', '0').replace(',', '')),
                          trader_pnl=float(fields.get('pnl', '0').replace(',', '')),
                          raw_text=text, outcome='pushed')
    else:
        # 需要确认或减仓信号
        msg = format_message(fields, rec, signal_type)
        _tracker_record(trader=trader, symbol=symbol, side=side,
                      leverage=int(leverage) if leverage else 10,
                      trader_size=float(fields.get('size', '0').replace(',', '')),
                      trader_entry=float(fields.get('entry', '0').replace(',', '')),
                      trader_pnl=float(fields.get('pnl', '0').replace(',', '')),
                      raw_text=text, outcome='pushed')

    # 记录去重
    record_signal(dedup_conn, text, symbol, trader)
    dedup_conn.close()

    # 推送
    success = push_to_qq(msg)
    if success:
        return f"✅ 已推送 | {symbol} {side} {leverage}x | {rec['contracts']}张 | 性价比{rec.get('cost_check', {}).get('rating_text', '?')}"
    else:
        return f"❌ 推送失败"

def main():
    if len(sys.argv) > 1:
        text = ' '.join(sys.argv[1:])
    else:
        text = sys.stdin.read()

    if not text.strip():
        print("用法: python3 process_signal.py '信号文本'")
        print("或: echo '信号文本' | python3 process_signal.py")
        return

    result = process_signal(text)
    print(result)

if __name__ == '__main__':
    main()
