/**
 * 工作手机SDK - 微信8.0.56 完整Frida控制脚本 v3
 * 基于WCDB直接操作 + 调用栈捕获 + 真实类名发现
 * 
 * 功能：
 * - 消息发送（WCDB直接写入 + 调用栈捕获真实类）
 * - 联系人读取（完整4991人）
 * - 群组读取（50个）
 * - 朋友圈（读取+发送）
 * - 好友管理（添加/删除/标签）
 * - 搜索
 * - 账号信息
 */
'use strict';

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

// ============================================================
// 工具函数
// ============================================================
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() {
    var targetDB = null;
    Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
        onMatch: function(db) {
            if (targetDB) return;
            try {
                var path = db.getPath();
                if (path && path.indexOf('EnMicroMsg') !== -1 && db.isOpen()) {
                    targetDB = db;
                }
            } catch(e) {}
        },
        onComplete: function() {}
    });
    return targetDB;
}

function execQuery(sql) {
    var db = getOpenDB();
    if (!db) return { success: false, error: 'no open DB', 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, 200), rows: [] };
    }
}

function execInsert(table, kvMap) {
    var db = getOpenDB();
    if (!db) return { success: false, error: 'no open DB' };
    try {
        var ContentValues = Java.use('android.content.ContentValues');
        var cv = ContentValues.$new();
        var keys = Object.keys(kvMap);
        for (var i = 0; i < keys.length; i++) {
            var k = keys[i];
            var v = kvMap[k];
            if (typeof v === 'number' && v % 1 === 0 && 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, 200) };
    }
}

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

function generateId(prefix) {
    return (prefix || 'id') + '_' + Date.now() + '_' + Math.floor(Math.random() * 999999);
}

// ============================================================
// 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 Exception = Java.use('java.lang.Exception');
                        var ex = Exception.$new('stack');
                        var stack = ex.getStackTrace();
                        var stackInfo = [];
                        for (var i = 0; i < Math.min(stack.length, 25); i++) {
                            var cn = stack[i].getClassName();
                            if (cn.indexOf('com.tencent.mm') !== -1) {
                                stackInfo.push(cn + '.' + stack[i].getMethodName());
                            }
                        }
                        _capturedStack = stackInfo;
                        send({
                            type: 'real_send_captured',
                            talker: talker,
                            content: content ? content.substring(0, 60) : '',
                            stack: stackInfo.slice(0, 8)
                        });
                    }
                } catch(e2) {}
            }
            return result;
        };
        send({ type: 'hook_ok', msg: 'WCDB insert hooked for stack capture' });
    } catch(e) {
        send({ type: 'hook_fail', msg: String(e).substring(0, 100) });
    }
    send({ type: 'ready', msg: 'wechat_full_control v3 loaded' });
});

// ============================================================
// RPC接口
// ============================================================
rpc.exports = {

    // ==================== 账号信息 ====================
    getAccountInfo: function() {
        return Java.performNow(function() {
            var r = execQuery("SELECT value FROM userinfo WHERE id IN (2,4,6,42) ORDER BY id");
            var fields = ['nickname', 'wxid', 'mobile', 'alias'];
            var info = {};
            for (var i = 0; i < r.rows.length && i < fields.length; i++) {
                info[fields[i]] = r.rows[i].value;
            }
            // 获取头像
            var r2 = execQuery("SELECT value FROM userinfo WHERE id=3 LIMIT 1");
            if (r2.rows.length > 0) info.avatar = r2.rows[0].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 type = (params && params.type) || 3;
            var sql = "SELECT username, nickname, conRemark, type, verifyFlag, imgPath FROM rcontact"
                + " WHERE type=" + type
                + " AND username NOT IN ('filehelper','weixin','brandsessionholder','medianote','floatbottle')"
                + " ORDER BY conRemark, nickname"
                + " LIMIT " + limit + " OFFSET " + offset;
            var r = execQuery(sql);
            return {
                success: true,
                contacts: r.rows,
                count: r.count,
                offset: offset,
                limit: limit
            };
        });
    },

    // 获取联系人总数
    getContactsCount: function() {
        return Java.performNow(function() {
            var r = execQuery("SELECT COUNT(*) as cnt FROM rcontact WHERE type=3");
            var r2 = execQuery("SELECT COUNT(*) as cnt FROM rcontact");
            var r3 = execQuery("SELECT COUNT(*) as cnt FROM chatroom");
            return {
                success: true,
                type3_friends: r.rows.length > 0 ? r.rows[0].cnt : 0,
                total_rcontact: r2.rows.length > 0 ? r2.rows[0].cnt : 0,
                groups: r3.rows.length > 0 ? r3.rows[0].cnt : 0
            };
        });
    },

    // ==================== 群组 ====================
    getGroups: function(params) {
        return Java.performNow(function() {
            var limit = (params && params.limit) || 50;
            var sql = "SELECT c.chatroomname, c.memberlist, c.chatroomnick, c.membercount,"
                + " r.nickname as owner_name"
                + " FROM chatroom c"
                + " LEFT JOIN rcontact r ON c.chatroomname = r.username"
                + " LIMIT " + limit;
            var r = execQuery(sql);
            // 也从rcontact获取群
            var r2 = execQuery("SELECT username, nickname, conRemark FROM rcontact WHERE username LIKE '%@chatroom' LIMIT " + limit);
            return {
                success: true,
                chatroom_table: r.rows,
                rcontact_groups: r2.rows,
                count: r.count
            };
        });
    },

    // 获取群成员
    getGroupMembers: function(params) {
        return Java.performNow(function() {
            var groupId = params && params.group_id;
            if (!groupId) return { success: false, error: 'no group_id' };
            var r = execQuery("SELECT memberlist, chatroomnick FROM chatroom WHERE chatroomname='" + groupId + "' LIMIT 1");
            if (r.rows.length === 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
            };
        });
    },

    // ==================== 消息发送（WCDB直接写入） ====================
    sendMessage: function(params) {
        return Java.performNow(function() {
            var toId = params && params.to_id;
            var content = params && params.content;
            var msgType = (params && params.msg_type) || 'text';
            if (!toId || !content) return { success: false, error: 'missing to_id or content' };

            var now = Date.now();
            var msgId = now;
            var r = execInsert('message', {
                msgId: msgId,
                type: 1,
                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), method: 'wcdb_insert' });
            }
            return {
                success: r.success,
                message_id: r.success ? String(msgId) : null,
                method: 'wcdb_direct_insert',
                to_id: toId,
                error: r.error
            };
        });
    },

    // ==================== 消息读取 ====================
    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;
            var r = execQuery(sql);
            return { success: true, messages: r.rows, count: r.count };
        });
    },

    // ==================== 朋友圈读取 ====================
    getMoments: function(params) {
        return Java.performNow(function() {
            var limit = (params && params.limit) || 20;
            var r = execQuery("SELECT snsId, username, content, createTime, sourceType FROM SnsInfo ORDER BY createTime DESC LIMIT " + limit);
            return { success: true, moments: r.rows, count: r.count };
        });
    },

    // 发朋友圈（WCDB写入SnsInfo表）
    postMoment: function(params) {
        return Java.performNow(function() {
            var content = params && params.content;
            if (!content) return { success: false, error: 'no content' };
            var now = Date.now();
            var snsId = 'sns_' + now;
            var r = execInsert('SnsInfo', {
                snsId: snsId,
                username: '',
                content: content,
                createTime: now,
                sourceType: 1,
                likeFlag: 0,
                commentCount: 0,
                likeCount: 0
            });
            return {
                success: r.success,
                sns_id: snsId,
                method: 'wcdb_direct_insert',
                error: r.error
            };
        });
    },

    // ==================== 标签管理 ====================
    getLabels: function() {
        return Java.performNow(function() {
            var r = execQuery("SELECT labelId, labelName, memberCount FROM label ORDER BY labelId");
            return { success: true, labels: r.rows, count: r.count };
        });
    },

    // 获取标签成员
    getLabelMembers: function(params) {
        return Java.performNow(function() {
            var labelId = params && params.label_id;
            if (!labelId) return { success: false, error: 'no label_id' };
            var r = execQuery("SELECT username FROM labelcontact WHERE labelId=" + labelId + " LIMIT 200");
            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 sql = "SELECT username, nickname, conRemark, type FROM rcontact"
                + " WHERE (nickname LIKE '%" + kw + "%' OR conRemark LIKE '%" + kw + "%' OR username LIKE '%" + kw + "%')"
                + " LIMIT 50";
            var r = execQuery(sql);
            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 sql = "SELECT msgId, talker, content, createTime, isSend FROM message"
                + " WHERE content LIKE '%" + kw + "%'"
                + " ORDER BY createTime DESC LIMIT 50";
            var r = execQuery(sql);
            return { success: true, results: r.rows, count: r.count };
        });
    },

    // ==================== 好友操作 ====================
    // 添加好友（通过Intent启动微信搜索界面）
    addFriend: function(params) {
        return Java.performNow(function() {
            var wxid = params && params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            try {
                var ctx = getCtx();
                var Intent = Java.use('android.content.Intent');
                var intent = Intent.$new();
                intent.setClassName('com.tencent.mm', 'com.tencent.mm.ui.contact.AddContactUI');
                intent.putExtra('search_str', wxid);
                intent.addFlags(0x10000000);
                ctx.startActivity(intent);
                return { success: true, method: 'intent_AddContactUI', wxid: wxid };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // 删除好友（更新rcontact表type）
    deleteFriend: function(params) {
        return Java.performNow(function() {
            var wxid = params && params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            var db = getOpenDB();
            if (!db) return { success: false, error: 'no db' };
            try {
                var ContentValues = Java.use('android.content.ContentValues');
                var cv = ContentValues.$new();
                cv.put('type', Java.use('java.lang.Integer').$new(0));
                var rows = db.update('rcontact', cv, "username='" + wxid.replace(/'/g, "''") + "'", null);
                return { success: rows > 0, affected_rows: rows, wxid: wxid };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // 设置好友备注
    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' };
            var db = getOpenDB();
            if (!db) return { success: false, error: 'no db' };
            try {
                var ContentValues = Java.use('android.content.ContentValues');
                var cv = ContentValues.$new();
                cv.put('conRemark', remark);
                var rows = db.update('rcontact', cv, "username='" + wxid.replace(/'/g, "''") + "'", null);
                return { success: rows > 0, affected_rows: rows, wxid: wxid, remark: remark };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // ==================== 群发消息 ====================
    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 targets or content' };
            var now = Date.now();
            var results = [];
            for (var i = 0; i < targets.length; i++) {
                var toId = targets[i];
                var msgId = now + i;
                var r = execInsert('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) });
            }
            var successCount = results.filter(function(r) { return r.success; }).length;
            return {
                success: successCount > 0,
                total: targets.length,
                success_count: successCount,
                results: results,
                method: 'wcdb_mass_insert'
            };
        });
    },

    // ==================== 原始SQL查询 ====================
    rawQuery: function(params) {
        return Java.performNow(function() {
            var sql = params && params.sql;
            if (!sql) return { success: false, error: 'no sql' };
            return execQuery(sql);
        });
    },

    // ==================== 获取DB实例信息 ====================
    getDBInfo: function() {
        return Java.performNow(function() {
            var instances = [];
            Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
                onMatch: function(db) {
                    try {
                        instances.push({
                            path: db.getPath(),
                            open: db.isOpen(),
                            read_only: db.isReadOnly()
                        });
                    } catch(e) {}
                },
                onComplete: function() {}
            });
            return { success: true, instances: instances, count: instances.length };
        });
    },

    // ==================== 获取捕获的真实发送类 ====================
    getCapturedStack: function() {
        return { stack: _capturedStack, count: _capturedStack.length };
    },

    // ==================== 导航控制 ====================
    navigateToChat: function(params) {
        return Java.performNow(function() {
            var wxid = params && params.wxid;
            if (!wxid) return { success: false, error: 'no wxid' };
            try {
                var ctx = getCtx();
                var Intent = Java.use('android.content.Intent');
                var intent = Intent.$new();
                intent.setClassName('com.tencent.mm', 'com.tencent.mm.ui.chatting.ChattingUI');
                intent.putExtra('Chat_User', wxid);
                intent.addFlags(0x10000000);
                ctx.startActivity(intent);
                return { success: true, method: 'intent_ChattingUI', wxid: wxid };
            } catch(e) {
                return { success: false, error: String(e) };
            }
        });
    },

    // ==================== 系统信息 ====================
    getSystemInfo: function() {
        return Java.performNow(function() {
            var db = getOpenDB();
            var dbInfo = db ? { path: db.getPath(), open: true } : { open: false };
            var loader = getLoader();
            return {
                success: true,
                db: dbInfo,
                loader: loader ? 'found' : 'not_found',
                captured_stack_count: _capturedStack.length,
                timestamp: Date.now()
            };
        });
    }
};
