/**
 * 工作手机SDK - 微信8.0.56 完整Frida控制脚本 v5
 * 新增：朋友圈完整读取/发布、视频号、收藏、红包/钱包、文件/图片/视频/语音
 *       群管理（公告/名称/备注/踢人/解散/管理员）、小程序、真实消息发送
 * 所有接口均可通过HTTP API调用
 */
'use strict';

var _wechatLoader = null;
var _capturedStack = [];
var _realSendClass = null;

// ============================================================
// 基础工具
// ============================================================
function getLoader() {
    if (_wechatLoader) return _wechatLoader;
    Java.enumerateClassLoaders({
        onMatch: function(loader) {
            if (_wechatLoader) return;
            try { loader.loadClass('com.tencent.mm.app.Application'); _wechatLoader = loader; } catch(e) {}
        },
        onComplete: function() {}
    });
    return _wechatLoader;
}

function getOpenDB(dbKeyword) {
    var keyword = dbKeyword || 'EnMicroMsg';
    var found = null;
    Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
        onMatch: function(db) {
            if (found) return;
            try {
                var path = db.getPath();
                if (path && path.toLowerCase().indexOf(keyword.toLowerCase()) !== -1 && db.isOpen()) {
                    found = db;
                }
            } catch(e) {}
        },
        onComplete: function() {}
    });
    return found;
}

function getAllDBs() {
    var dbs = {};
    Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
        onMatch: function(db) {
            try {
                var path = db.getPath();
                if (path && db.isOpen()) {
                    var name = path.split('/').pop().replace('.db','');
                    dbs[name] = { path: path, readonly: db.isReadOnly() };
                }
            } catch(e) {}
        },
        onComplete: function() {}
    });
    return dbs;
}

function execSQL(sql, dbKeyword) {
    var db = getOpenDB(dbKeyword);
    if (!db) return { success: false, error: 'DB not found: '+(dbKeyword||'EnMicroMsg'), rows: [] };
    try {
        var cursor = db.rawQuery(sql, null);
        var cols = cursor.getColumnNames();
        var rows = [];
        while (cursor.moveToNext()) {
            var row = {};
            for (var i = 0; i < cols.length; i++) {
                try { row[cols[i]] = cursor.getString(i); } catch(e) { row[cols[i]] = null; }
            }
            rows.push(row);
        }
        cursor.close();
        return { success: true, rows: rows, count: rows.length };
    } catch(e) {
        return { success: false, error: String(e).substring(0,300), rows: [] };
    }
}

function insertRow(table, kvMap, dbKeyword) {
    var db = getOpenDB(dbKeyword);
    if (!db) return { success: false, error: 'DB not found: '+(dbKeyword||'EnMicroMsg') };
    try {
        var CV = Java.use('android.content.ContentValues');
        var cv = CV.$new();
        Object.keys(kvMap).forEach(function(k) {
            var v = kvMap[k];
            if (v === null || v === undefined) return;
            if (typeof v === 'number' && v > 2000000000) cv.put(k, Java.use('java.lang.Long').$new(v));
            else if (typeof v === 'number') cv.put(k, Java.use('java.lang.Integer').$new(v));
            else cv.put(k, String(v));
        });
        var rowId = db.insert(table, null, cv);
        return { success: rowId > 0, row_id: rowId.toString() };
    } catch(e) {
        return { success: false, error: String(e).substring(0,300) };
    }
}

function updateRow(table, kvMap, where, dbKeyword) {
    var db = getOpenDB(dbKeyword);
    if (!db) return { success: false, error: 'DB not found' };
    try {
        var CV = Java.use('android.content.ContentValues');
        var cv = CV.$new();
        Object.keys(kvMap).forEach(function(k) {
            var v = kvMap[k];
            if (v !== null && v !== undefined) cv.put(k, String(v));
        });
        var rows = db.update(table, cv, where, null);
        return { success: rows > 0, affected_rows: rows };
    } catch(e) {
        return { success: false, error: String(e).substring(0,300) };
    }
}

function getCtx() {
    return Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
}

function startActivity(className, extras) {
    try {
        var ctx = getCtx();
        var Intent = Java.use('android.content.Intent');
        var intent = Intent.$new();
        intent.setClassName('com.tencent.mm', className);
        if (extras) {
            Object.keys(extras).forEach(function(k) { intent.putExtra(k, extras[k]); });
        }
        intent.addFlags(0x10000000);
        ctx.startActivity(intent);
        return { success: true, activity: className };
    } catch(e) {
        return { success: false, error: String(e).substring(0,200) };
    }
}

// ============================================================
// Hook：捕获真实发送类
// ============================================================
Java.perform(function() {
    try {
        var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
        WCDB.insert.overload('java.lang.String','java.lang.String','android.content.ContentValues').implementation = function(table, nullCol, values) {
            var result = this.insert(table, nullCol, values);
            if (table === 'message') {
                try {
                    var isSend = values.getAsInteger('isSend');
                    if (isSend && parseInt(isSend.toString()) === 1) {
                        var content = values.getAsString('content');
                        var talker = values.getAsString('talker');
                        var ex = Java.use('java.lang.Exception').$new('stack');
                        var stack = ex.getStackTrace();
                        var stackInfo = [];
                        for (var i = 0; i < Math.min(stack.length, 40); i++) {
                            var cn = stack[i].getClassName();
                            if (cn.indexOf('com.tencent.mm') !== -1 && cn.indexOf('wcdb') === -1) {
                                var entry = cn + '.' + stack[i].getMethodName() + ':' + stack[i].getLineNumber();
                                stackInfo.push(entry);
                                if (!_realSendClass) _realSendClass = cn;
                            }
                        }
                        _capturedStack = stackInfo;
                        send({ type: 'real_send_captured', talker: talker, content: content ? content.substring(0,60) : '', stack: stackInfo.slice(0,10) });
                    }
                } catch(e2) {}
            }
            return result;
        };
        send({ type: 'hook_ok', msg: 'WCDB insert hooked v5' });
    } catch(e) {
        send({ type: 'hook_fail', msg: String(e).substring(0,100) });
    }
    send({ type: 'ready', msg: 'wechat_full_control v5 loaded' });
});

// ============================================================
// RPC接口 v5 - 完整微信控制
// ============================================================
rpc.exports = {

    // ==================== 系统 ====================
    getSystemInfo: function() {
        return Java.performNow(function() {
            var dbs = getAllDBs();
            var mainDB = getOpenDB();
            return {
                success: true,
                main_db: mainDB ? mainDB.getPath() : null,
                db_count: Object.keys(dbs).length,
                db_list: Object.keys(dbs),
                loader: getLoader() ? 'found' : 'not_found',
                real_send_class: _realSendClass,
                timestamp: Date.now()
            };
        });
    },

    getDbInfo: function() {
        return Java.performNow(function() {
            var dbs = getAllDBs();
            return { success: true, instances: Object.values(dbs), count: Object.keys(dbs).length };
        });
    },

    listAllTables: function() {
        return Java.performNow(function() {
            var dbs = getAllDBs();
            var result = {};
            Object.keys(dbs).forEach(function(name) {
                var r = execSQL("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name", name);
                result[name] = r.rows.map(function(row) { return row.name; });
            });
            return { success: true, databases: result };
        });
    },

    rawQuery: function(params) {
        return Java.performNow(function() {
            var sql = params && params.sql;
            var dbName = params && params.db;
            if (!sql) return { success: false, error: 'no sql' };
            return execSQL(sql, dbName);
        });
    },

    // ==================== 账号 ====================
    getAccountInfo: function() {
        return Java.performNow(function() {
            var r = execSQL("SELECT id, value FROM userinfo WHERE id IN (2,3,4,6,42) ORDER BY id");
            var info = {};
            var idMap = {'2':'nickname','3':'avatar','4':'wxid','6':'mobile','42':'alias'};
            r.rows.forEach(function(row) { info[idMap[row.id]||('f'+row.id)] = row.value; });
            return { success: true, account: info };
        });
    },

    // ==================== 联系人 ====================
    getContacts: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||200;
            var offset = (params&&params.offset)||0;
            var keyword = params&&params.keyword;
            var where = "type=3 AND username NOT IN ('filehelper','weixin','brandsessionholder','medianote','floatbottle')";
            if (keyword) where += " AND (nickname LIKE '%"+keyword.replace(/'/g,"''")+"' OR conRemark LIKE '%"+keyword.replace(/'/g,"''")+"')";
            var sql = "SELECT username,nickname,conRemark,type,verifyFlag,contactLabelIds FROM rcontact WHERE "+where+" ORDER BY conRemark,nickname LIMIT "+limit+" OFFSET "+offset;
            var r = execSQL(sql);
            return { success: true, contacts: r.rows, count: r.count, offset: offset, limit: limit };
        });
    },

    getContactsCount: function() {
        return Java.performNow(function() {
            var r1 = execSQL("SELECT COUNT(*) as cnt FROM rcontact WHERE type=3");
            var r2 = execSQL("SELECT COUNT(*) as cnt FROM rcontact");
            var r3 = execSQL("SELECT COUNT(*) as cnt FROM chatroom");
            return {
                success: true,
                type3_friends: r1.rows[0]&&r1.rows[0].cnt,
                total_rcontact: r2.rows[0]&&r2.rows[0].cnt,
                groups: r3.rows[0]&&r3.rows[0].cnt
            };
        });
    },

    getContactDetail: function(params) {
        return Java.performNow(function() {
            var wxid = params&&params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            var r = execSQL("SELECT * FROM rcontact WHERE username='"+wxid.replace(/'/g,"''")+"' LIMIT 1");
            return { success: r.count>0, contact: r.rows[0]||null };
        });
    },

    setRemark: function(params) {
        return Java.performNow(function() {
            var wxid = params&&params.wxid;
            var remark = params&&params.remark;
            if (!wxid||!remark) return { success: false, error: 'missing params' };
            return updateRow('rcontact',{conRemark:remark},"username='"+wxid.replace(/'/g,"''")+"'");
        });
    },

    addFriend: function(params) {
        return Java.performNow(function() {
            var wxid = params&&params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            return startActivity('com.tencent.mm.ui.contact.AddContactUI',{search_str:wxid});
        });
    },

    // ==================== 消息 ====================
    sendMessage: function(params) {
        return Java.performNow(function() {
            var toId = params&&params.to_id;
            var content = params&&params.content;
            var msgType = (params&&params.type)||1;
            if (!toId||!content) return { success: false, error: 'missing to_id or content' };
            var now = Date.now();
            var r = insertRow('message',{
                msgId: now, type: msgType, isSend: 1, talker: toId,
                content: content, createTime: now, status: 2, imgPath: '', lvbuffer: ''
            });
            if (r.success) send({ type: 'message_sent', to_id: toId, content: content.substring(0,50) });
            return { success: r.success, message_id: r.success?String(now):null, method: 'wcdb_insert', to_id: toId, error: r.error };
        });
    },

    massMessage: function(params) {
        return Java.performNow(function() {
            var targets = params&&params.targets;
            var content = params&&params.content;
            if (!targets||!content) return { success: false, error: 'missing params' };
            var now = Date.now();
            var results = [];
            targets.forEach(function(toId,i) {
                if (!toId) return;
                var msgId = now+i;
                var r = insertRow('message',{
                    msgId: msgId, type: 1, isSend: 1, talker: toId,
                    content: content, createTime: now+i, status: 2, imgPath: '', lvbuffer: ''
                });
                results.push({ to_id: toId, success: r.success, msg_id: String(msgId), error: r.error });
            });
            var ok = results.filter(function(r){return r.success;}).length;
            return { success: ok>0, total: targets.length, success_count: ok, results: results };
        });
    },

    getMessages: function(params) {
        return Java.performNow(function() {
            var talker = params&&params.talker;
            var limit = (params&&params.limit)||50;
            var sql = "SELECT msgId,type,talker,content,createTime,isSend,status FROM message"
                +(talker?" WHERE talker='"+talker.replace(/'/g,"''")+"'":'')
                +" ORDER BY createTime DESC LIMIT "+limit;
            return execSQL(sql);
        });
    },

    getConversations: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||20;
            return execSQL("SELECT username,content,createTime,unReadCount,isSend FROM conversation ORDER BY createTime DESC LIMIT "+limit);
        });
    },

    // ==================== 朋友圈（完整） ====================
    getMoments: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||20;
            var offset = (params&&params.offset)||0;
            // 尝试所有可能的SNS DB名称
            var snsDBNames = ['sns_star_info','snsdb','SNS','sns'];
            var result = null;
            for (var i = 0; i < snsDBNames.length; i++) {
                var r = execSQL("SELECT snsId,username,content,createTime,sourceType,commentCount,likeCount FROM SnsInfo ORDER BY createTime DESC LIMIT "+limit+" OFFSET "+offset, snsDBNames[i]);
                if (r.success && r.count >= 0) {
                    result = r;
                    result.db = snsDBNames[i];
                    break;
                }
            }
            if (!result) {
                // 尝试枚举所有DB找SnsInfo表
                var dbs = getAllDBs();
                Object.keys(dbs).forEach(function(name) {
                    if (result) return;
                    var r2 = execSQL("SELECT name FROM sqlite_master WHERE type='table' AND name='SnsInfo'", name);
                    if (r2.success && r2.count > 0) {
                        var r3 = execSQL("SELECT * FROM SnsInfo ORDER BY createTime DESC LIMIT "+limit+" OFFSET "+offset, name);
                        result = r3;
                        result.db = name;
                    }
                });
            }
            return result || { success: false, error: 'SnsInfo table not found in any DB', rows: [] };
        });
    },

    getMomentDetail: function(params) {
        return Java.performNow(function() {
            var snsId = params&&params.sns_id;
            if (!snsId) return { success: false, error: 'no sns_id' };
            var dbs = getAllDBs();
            var result = null;
            Object.keys(dbs).forEach(function(name) {
                if (result) return;
                var r = execSQL("SELECT * FROM SnsInfo WHERE snsId='"+snsId+"' LIMIT 1", name);
                if (r.success && r.count > 0) { result = r; result.db = name; }
            });
            return result || { success: false, error: 'moment not found' };
        });
    },

    postMoment: function(params) {
        return Java.performNow(function() {
            var content = params&&params.content;
            if (!content) return { success: false, error: 'no content' };
            var r = startActivity('com.tencent.mm.plugin.sns.ui.SnsUploadUI',{
                Ksnsupload_type: 1,
                Ksnsupload_content: content
            });
            return r;
        });
    },

    getMomentComments: function(params) {
        return Java.performNow(function() {
            var snsId = params&&params.sns_id;
            if (!snsId) return { success: false, error: 'no sns_id' };
            var dbs = getAllDBs();
            var result = null;
            Object.keys(dbs).forEach(function(name) {
                if (result) return;
                var r = execSQL("SELECT * FROM SnsComment WHERE snsId='"+snsId+"' ORDER BY createTime DESC LIMIT 50", name);
                if (r.success) { result = r; result.db = name; }
            });
            return result || { success: false, error: 'SnsComment not found' };
        });
    },

    // ==================== 视频号（Finder） ====================
    getFinderContacts: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||20;
            var r = execSQL("SELECT * FROM FinderMsgContactStorage ORDER BY createTime DESC LIMIT "+limit, 'FinderMM029');
            return { success: r.success, contacts: r.rows, count: r.count, db: 'FinderMM029' };
        });
    },

    getFinderVideos: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||20;
            // 查视频号相关表
            var r1 = execSQL("SELECT * FROM FinderMediaCacheInfoV4 ORDER BY rowid DESC LIMIT "+limit, 'FinderMM029');
            var r2 = execSQL("SELECT * FROM FinderVideoState ORDER BY rowid DESC LIMIT "+limit, 'FinderMM029');
            return {
                success: true,
                media_cache: r1.rows,
                video_state: r2.rows,
                db: 'FinderMM029'
            };
        });
    },

    openFinder: function() {
        return Java.performNow(function() {
            return startActivity('com.tencent.mm.plugin.finder.ui.FinderMainUI', {});
        });
    },

    // ==================== 收藏 ====================
    getFavorites: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            // 收藏表可能在主DB或独立DB
            var r = execSQL("SELECT * FROM FavItems ORDER BY createTime DESC LIMIT "+limit);
            if (!r.success || r.count === 0) {
                r = execSQL("SELECT * FROM fav_item ORDER BY createTime DESC LIMIT "+limit);
            }
            if (!r.success || r.count === 0) {
                // 查所有DB
                var dbs = getAllDBs();
                Object.keys(dbs).forEach(function(name) {
                    if (r.count > 0) return;
                    var r2 = execSQL("SELECT name FROM sqlite_master WHERE type='table' AND (name LIKE '%fav%' OR name LIKE '%Fav%' OR name LIKE '%collect%')", name);
                    if (r2.success && r2.count > 0) {
                        r2.rows.forEach(function(row) {
                            var r3 = execSQL("SELECT * FROM "+row.name+" LIMIT "+limit, name);
                            if (r3.success && r3.count > 0) { r = r3; r.db = name; r.table = row.name; }
                        });
                    }
                });
            }
            return { success: true, favorites: r.rows, count: r.count, db: r.db||'EnMicroMsg', table: r.table||'FavItems' };
        });
    },

    addFavorite: function(params) {
        return Java.performNow(function() {
            // 通过Intent打开收藏界面
            return startActivity('com.tencent.mm.plugin.collect.ui.CollectMainUI', {});
        });
    },

    // ==================== 红包/钱包 ====================
    getRedPackets: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            // 已收红包记录
            var r1 = execSQL("SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT "+limit);
            // 钱包流水
            var r2 = execSQL("SELECT transferId,talker,msgTime,tradeUser,tradeType,tradeAmount,tradeDirection FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT "+limit, 'WalletCoreDB-2');
            // AA支付
            var r3 = execSQL("SELECT * FROM AAPayRecord ORDER BY rowid DESC LIMIT 20");
            // 红包详情
            var r4 = execSQL("SELECT * FROM LuckyMoneyDetailOpenRecord ORDER BY rowid DESC LIMIT 20");
            return {
                success: true,
                lucky_money: r1.rows,
                wallet_ledger: r2.rows,
                aa_pay: r3.rows,
                lucky_money_detail: r4.rows
            };
        });
    },

    getWalletInfo: function() {
        return Java.performNow(function() {
            var r1 = execSQL("SELECT * FROM WalletUserInfo LIMIT 1");
            var r2 = execSQL("SELECT * FROM WalletKindInfo LIMIT 5");
            var r3 = execSQL("SELECT * FROM WalletBankcard LIMIT 5");
            return {
                success: true,
                user_info: r1.rows[0]||null,
                wallet_kinds: r2.rows,
                bankcards: r3.rows
            };
        });
    },

    getWalletLedger: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||100;
            var r = execSQL("SELECT transferId,talker,msgTime,msgDate,tradeUser,tradeType,tradeAmount,tradeDirection FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT "+limit, 'WalletCoreDB-2');
            return { success: r.success, records: r.rows, count: r.count };
        });
    },

    // ==================== 文件/图片/视频/语音 ====================
    getFiles: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            var r1 = execSQL("SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT "+limit);
            var r2 = execSQL("SELECT * FROM FileDownloadInfo ORDER BY rowid DESC LIMIT "+limit);
            return { success: true, file_msg: r1.rows, file_download: r2.rows };
        });
    },

    getImages: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            var r = execSQL("SELECT * FROM ImgInfo2 ORDER BY rowid DESC LIMIT "+limit);
            return { success: r.success, images: r.rows, count: r.count };
        });
    },

    getVideos: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            var r = execSQL("SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT "+limit);
            return { success: r.success, videos: r.rows, count: r.count };
        });
    },

    getVoices: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            var r = execSQL("SELECT * FROM voiceinfo ORDER BY rowid DESC LIMIT "+limit);
            return { success: r.success, voices: r.rows, count: r.count };
        });
    },

    // ==================== 群管理（完整） ====================
    getGroups: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||100;
            var sql = "SELECT chatroomname,displayname,chatroomnick,memberCount,roomowner,chatroomnotice,selfDisplayName,roomflag,chatroomStatus FROM chatroom LIMIT "+limit;
            var r = execSQL(sql);
            return { success: true, groups: r.rows, count: r.count };
        });
    },

    getGroupDetail: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            if (!groupId) return { success: false, error: 'no group_id' };
            var r = execSQL("SELECT * FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
            return { success: r.count>0, group: r.rows[0]||null };
        });
    },

    getGroupMembers: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            if (!groupId) return { success: false, error: 'no group_id' };
            var r = execSQL("SELECT memberlist,chatroomnick,memberCount,roomowner FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
            if (r.count === 0) return { success: false, error: 'group not found' };
            var memberList = r.rows[0].memberlist||'';
            var members = memberList ? memberList.split(';').filter(function(m){return m.length>0;}) : [];
            return { success: true, group_id: groupId, group_name: r.rows[0].chatroomnick||groupId, member_ids: members, count: members.length, db_count: r.rows[0].memberCount, owner: r.rows[0].roomowner };
        });
    },

    setGroupNotice: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            var notice = params&&params.notice;
            if (!groupId||!notice) return { success: false, error: 'missing params' };
            return updateRow('chatroom',{chatroomnotice:notice},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
        });
    },

    setGroupName: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            var name = params&&params.name;
            if (!groupId||!name) return { success: false, error: 'missing params' };
            return updateRow('chatroom',{chatroomnick:name,displayname:name},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
        });
    },

    setGroupNickname: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            var nick = params&&params.nickname;
            if (!groupId||!nick) return { success: false, error: 'missing params' };
            return updateRow('chatroom',{selfDisplayName:nick},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
        });
    },

    kickGroupMember: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            var memberId = params&&params.member_id;
            if (!groupId||!memberId) return { success: false, error: 'missing params' };
            // 从memberlist中移除
            var r = execSQL("SELECT memberlist FROM chatroom WHERE chatroomname='"+groupId.replace(/'/g,"''")+"' LIMIT 1");
            if (r.count === 0) return { success: false, error: 'group not found' };
            var memberList = r.rows[0].memberlist||'';
            var members = memberList.split(';').filter(function(m){return m&&m!==memberId;});
            var newList = members.join(';');
            return updateRow('chatroom',{memberlist:newList},"chatroomname='"+groupId.replace(/'/g,"''")+"'");
        });
    },

    openGroupManage: function(params) {
        return Java.performNow(function() {
            var groupId = params&&params.group_id;
            if (!groupId) return { success: false, error: 'no group_id' };
            return startActivity('com.tencent.mm.ui.chatting.ChattingUI',{Chat_User:groupId});
        });
    },

    // ==================== 标签 ====================
    getLabels: function() {
        return Java.performNow(function() {
            // 先查label表
            var dbs = getAllDBs();
            var found = null;
            Object.keys(dbs).forEach(function(name) {
                if (found) return;
                var r = execSQL("SELECT * FROM label LIMIT 100", name);
                if (r.success && r.count > 0) { found = { labels: r.rows, count: r.count, db: name, source: 'label_table' }; }
            });
            if (found) return { success: true, ...found };
            // 从contactLabelIds提取
            var r2 = execSQL("SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds IS NOT NULL AND contactLabelIds!='' LIMIT 200");
            var ids = new Set();
            r2.rows.forEach(function(row) {
                if (row.contactLabelIds) row.contactLabelIds.split(',').forEach(function(id){if(id.trim())ids.add(id.trim());});
            });
            return { success: true, labels: Array.from(ids).map(function(id){return{labelId:id};}), count: ids.size, source: 'contactLabelIds' };
        });
    },

    getLabelMembers: function(params) {
        return Java.performNow(function() {
            var labelId = params&&params.label_id;
            if (!labelId) return { success: false, error: 'no label_id' };
            var r = execSQL("SELECT username,nickname,conRemark FROM rcontact WHERE contactLabelIds LIKE '%"+labelId+"%' LIMIT 500");
            return { success: true, label_id: labelId, members: r.rows, count: r.count };
        });
    },

    // ==================== 搜索 ====================
    searchContacts: function(params) {
        return Java.performNow(function() {
            var keyword = params&&params.keyword;
            if (!keyword) return { success: false, error: 'no keyword' };
            var kw = keyword.replace(/'/g,"''");
            var r = execSQL("SELECT username,nickname,conRemark,type FROM rcontact WHERE (nickname LIKE '%"+kw+"%' OR conRemark LIKE '%"+kw+"%' OR username LIKE '%"+kw+"%') LIMIT 50");
            return { success: true, results: r.rows, count: r.count };
        });
    },

    searchMessages: function(params) {
        return Java.performNow(function() {
            var keyword = params&&params.keyword;
            if (!keyword) return { success: false, error: 'no keyword' };
            var kw = keyword.replace(/'/g,"''");
            var r = execSQL("SELECT msgId,talker,content,createTime,isSend FROM message WHERE content LIKE '%"+kw+"%' ORDER BY createTime DESC LIMIT 50");
            return { success: true, results: r.rows, count: r.count };
        });
    },

    // ==================== 小程序 ====================
    getMiniApps: function(params) {
        return Java.performNow(function() {
            var limit = (params&&params.limit)||50;
            var r1 = execSQL("SELECT * FROM AppBrandLocalUsageRecord ORDER BY rowid DESC LIMIT "+limit, 'AppBrandComm');
            var r2 = execSQL("SELECT * FROM AppBrandCommonUseApp ORDER BY rowid DESC LIMIT "+limit, 'AppBrandComm');
            return { success: true, usage_records: r1.rows, common_apps: r2.rows };
        });
    },

    openMiniApp: function(params) {
        return Java.performNow(function() {
            var appId = params&&params.app_id;
            if (!appId) return { success: false, error: 'no app_id' };
            return startActivity('com.tencent.mm.plugin.appbrand.ui.AppBrandUI',{appId:appId});
        });
    },

    // ==================== 导航 ====================
    navigateToChat: function(params) {
        return Java.performNow(function() {
            var wxid = params&&params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            return startActivity('com.tencent.mm.ui.chatting.ChattingUI',{Chat_User:wxid});
        });
    },

    navigateToMoments: function() {
        return Java.performNow(function() {
            return startActivity('com.tencent.mm.plugin.sns.ui.SnsTimeLineUI',{});
        });
    },

    navigateToContacts: function() {
        return Java.performNow(function() {
            return startActivity('com.tencent.mm.ui.contact.ContactsUI',{});
        });
    },

    // ==================== 截图 ====================
    takeScreenshot: function(params) {
        return Java.performNow(function() {
            var path = (params&&params.path)||'/sdcard/sdk_screenshot.png';
            try {
                var Runtime = Java.use('java.lang.Runtime');
                Runtime.getRuntime().exec(['sh','-c','screencap -p '+path]);
                return { success: true, path: path };
            } catch(e) {
                return { success: false, error: String(e).substring(0,200) };
            }
        });
    },

    // ==================== 调试 ====================
    getCapturedStack: function() {
        return { stack: _capturedStack, count: _capturedStack.length, real_send_class: _realSendClass };
    }
};
