#!/usr/bin/env python3
# 工作手机 · Frida 主控通道·实机冒烟脚本（一次性跑完 8 项验证）
# 用法：python3 sdk/scripts/_hook_smoke.py <device_serial>
import json, sys, urllib.request, urllib.parse, time

DEVICE = sys.argv[1] if len(sys.argv) > 1 else 'xgfe65eimrrofyws'
BASE   = 'http://127.0.0.1:8899'

def get(path, params=None):
    url = f'{BASE}{path}'
    if params:
        url += '?' + urllib.parse.urlencode(params)
    with urllib.request.urlopen(url, timeout=60) as r:
        return json.loads(r.read())

def post(path, body):
    req = urllib.request.Request(
        f'{BASE}{path}',
        data=json.dumps(body).encode(),
        headers={'Content-Type': 'application/json'},
        method='POST',
    )
    with urllib.request.urlopen(req, timeout=120) as r:
        return json.loads(r.read())

def section(title):
    print('\n' + '=' * 60)
    print(f'  {title}')
    print('=' * 60)

def show(label, value, limit=200):
    s = json.dumps(value, ensure_ascii=False)
    if len(s) > limit:
        s = s[:limit] + ' …(truncated)'
    print(f'{label} → {s}')


# 1) probe
section('1) /api/v3/hook/probe — Hook 探测')
probe = get(f'/api/v3/hook/probe/{DEVICE}')
show('supports_hook', probe.get('supports_hook'))
show('frida_version', probe.get('frida_version'))
show('wechat_version', probe.get('wechat_version'))
show('profile.nickname', probe.get('profile', {}).get('profile', {}).get('nickname'))

# 2) actions 清单
section('2) /api/v3/hook/actions — 全部动作清单')
acts = get('/api/v3/hook/actions')
show('total_actions', acts.get('total_actions'))
show('total_modules', acts.get('total_modules'))

# 3) 一次性取数
section('3) /api/v3/hook/data — 取微信资料/联系人/群/消息/标签')
data = get(f'/api/v3/hook/data/{DEVICE}',
           {'modules': 'profile,contacts,groups,messages,labels'})
core = data.get('data', {})
def _list(node, key1, key2=None):
    inner = node.get('data', node)
    if key2 and isinstance(inner, dict) and key2 in inner:
        return inner[key2]
    if isinstance(inner, dict) and key1 in inner:
        return inner[key1]
    if isinstance(inner, dict) and 'data' in inner and isinstance(inner['data'], list):
        return inner['data']
    return inner if isinstance(inner, list) else []
contacts = _list(core['contacts'], 'contacts')
groups   = _list(core['groups'], 'groups')
messages = _list(core['messages'], 'messages')
labels   = _list(core['labels'], 'labels')
print(f'contacts : {len(contacts)} 条')
print(f'groups   : {len(groups)} 个')
print(f'messages : {len(messages)} 条')
print(f'labels   : {len(labels)} 个')
remark   = [c for c in contacts if c.get('remark')]
namedgrp = [g for g in groups if g.get('name')]
print(f'  - 有备注联系人: {len(remark)} ｜ 例子：',
      ', '.join((c.get('remark') or '?')[:24] for c in remark[:5]))
print(f'  - 已命名群    : {len(namedgrp)} ｜ 例子：',
      ', '.join((g.get('name') or '?')[:24] for g in namedgrp[:5]))
print(f'  - 标签        : {len(labels)} ｜ 例子：',
      ', '.join((l.get('name') or '?')[:18] for l in labels[:8]))

# 4) hookStatus / getMoments / getWechatVersion 直调
section('4) /api/v3/hook/execute — hookStatus + getWechatVersion')
hs = post('/api/v3/hook/execute', {
    'device_id': DEVICE, 'platform': 'wechat',
    'action': 'get_hook_status', 'params': {}, 'hook_only': True
})
show('hookStatus', hs)
gv = post('/api/v3/hook/execute', {
    'device_id': DEVICE, 'platform': 'wechat',
    'action': 'get_wechat_version', 'params': {}, 'hook_only': True
})
show('getWechatVersion', gv)

# 5) 朋友圈
section('5) /api/v3/hook/execute — getMoments(limit=3)')
mm = post('/api/v3/hook/execute', {
    'device_id': DEVICE, 'platform': 'wechat',
    'action': 'get_moments', 'params': {'limit': 3}, 'hook_only': True
})
show('getMoments', mm, 400)

# 6) 真发一条消息到文件传输助手
section('6) /api/v3/hook/execute — send_message → 文件传输助手')
ts = time.strftime('%H:%M:%S')
send = post('/api/v3/hook/execute', {
    'device_id': DEVICE, 'platform': 'wechat',
    'action': 'send_message',
    'params': {
        'to_id': 'filehelper',
        'content': f'[E2E] Frida 主控通道 实机冒烟 {ts}',
        'msg_type': 'text',
    },
    'hook_only': True
})
show('send_message', send)

# 7) 拉一条最近消息证明 read-back
section('7) /api/v3/hook/execute — get_recent_messages(limit=1)')
rm = post('/api/v3/hook/execute', {
    'device_id': DEVICE, 'platform': 'wechat',
    'action': 'get_recent_messages', 'params': {'limit': 1}, 'hook_only': True
})
show('get_recent_messages', rm, 400)

# 8) 走标准 unified channel=hook 的 sendMessage（验证存客宝侧路径）
section('8) /api/v3/message/send  channel=hook (存客宝标准入口)')
um = post('/api/v3/message/send', {
    'device_id': DEVICE, 'platform': 'wechat', 'to_id': 'filehelper',
    'content': f'[E2E] unified channel=hook {ts}',
    'msg_type': 'text', 'channel': 'hook'
})
show('unified.sendMessage', um, 400)

print('\n  ✅ Hook 主控冒烟测试完成')
