// 微信工作手机 SDK v8-fix - 全量Frida RPC接口
// 用Java.choose找到已加载的DB实例（已验证有效）
// 账号：游条姐 (wxid_5g37snchpv8e22)
'use strict';

var _dbs = {};  // name -> db instance

// ==================== DB初始化 ====================
function initAllDBs() {
    Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
        onMatch: function(db) {
            try {
                var p = db.getPath();
                if (!p) return;
                var name = p.split('/').pop().replace('.db','');
                if (p.indexOf('EnMicroMsg') > -1) _dbs['main'] = db;
                else if (p.indexOf('SnsMicroMsg') > -1) _dbs['sns'] = db;
                else if (p.indexOf('sns_star_info') > -1) _dbs['sns_star'] = db;
                else if (p.indexOf('WalletCoreDB-2') > -1) _dbs['wallet'] = db;
                else if (p.indexOf('WalletPay') > -1) _dbs['wallet2'] = db;
                else if (p.indexOf('FinderMM029') > -1) _dbs['finder'] = db;
                else if (p.indexOf('FinderMessage006') > -1) _dbs['finder2'] = db;
                else if (p.indexOf('FinderAccounts_01') > -1) _dbs['finder3'] = db;
                else if (p.indexOf('enFavorite') > -1) _dbs['favorite'] = db;
                else if (p.indexOf('FTS5IndexMicroMsg') > -1) _dbs['fts5'] = db;
                else if (p.indexOf('AppBrandComm') > -1) _dbs['appbrand'] = db;
                else if (p.indexOf('WxFileIndex') > -1) _dbs['wxfile'] = db;
                _dbs['_path_' + name] = db;
            } catch(e) {}
        },
        onComplete: function() {}
    });
}

function getDB(name) {
    if (!_dbs[name]) initAllDBs();
    return _dbs[name] || null;
}

function execSQL(db, sql, args) {
    if (!db) return {error: 'DB not available', rows: [], count: 0};
    try {
        var cursor;
        if (args && args.length > 0) {
            var jArgs = Java.array('java.lang.String', args.map(function(a) { return a ? String(a) : null; }));
            cursor = db.rawQuery(sql, jArgs);
        } else {
            cursor = db.rawQuery(sql, null);
        }
        var cols = [];
        var colCount = cursor.getColumnCount();
        for (var i = 0; i < colCount; i++) cols.push(cursor.getColumnName(i));
        var rows = [];
        while (cursor.moveToNext()) {
            var row = {};
            for (var j = 0; j < colCount; j++) {
                try { row[cols[j]] = cursor.getString(j); } catch(e) { row[cols[j]] = null; }
            }
            rows.push(row);
        }
        cursor.close();
        return {columns: cols, rows: rows, count: rows.length};
    } catch(e) {
        return {error: e.toString(), rows: [], count: 0};
    }
}

function writeSQL(db, sql) {
    if (!db) return {error: 'DB not available'};
    try {
        db.execSQL(sql);
        return {success: true};
    } catch(e) {
        return {error: e.toString()};
    }
}

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

    // ===== 系统 =====
    ping: function() {
        return {status: 'ok', version: 'v8-fix', timestamp: Date.now()};
    },

    initDbs: function() {
        initAllDBs();
        var status = {};
        ['main','sns','sns_star','wallet','wallet2','finder','finder2','finder3','favorite','fts5','appbrand'].forEach(function(n) {
            status[n] = !!_dbs[n];
        });
        return {status: status, total_dbs: Object.keys(_dbs).length};
    },

    listAllDbs: function() {
        initAllDBs();
        var list = [];
        Object.keys(_dbs).forEach(function(k) {
            if (!k.startsWith('_path_')) return;
            try {
                var db = _dbs[k];
                var p = db.getPath();
                list.push({name: k.replace('_path_',''), path: p});
            } catch(e) {}
        });
        return {dbs: list, count: list.length};
    },

    // ===== 账号 =====
    getAccountInfo: function() {
        var db = getDB('main');
        var wxid = execSQL(db, "SELECT value FROM userinfo WHERE id=2");
        var nick = execSQL(db, "SELECT value FROM userinfo WHERE id=6");
        var avatar = execSQL(db, "SELECT value FROM userinfo WHERE id=4");
        var phone = execSQL(db, "SELECT value FROM userinfo WHERE id=42");
        var region = execSQL(db, "SELECT value FROM userinfo WHERE id=44");
        var sex = execSQL(db, "SELECT value FROM userinfo WHERE id=12");
        return {
            wxid: wxid.rows[0] ? wxid.rows[0].value : null,
            nickname: nick.rows[0] ? nick.rows[0].value : null,
            avatar: avatar.rows[0] ? avatar.rows[0].value : null,
            phone: phone.rows[0] ? phone.rows[0].value : null,
            region: region.rows[0] ? region.rows[0].value : null,
            sex: sex.rows[0] ? sex.rows[0].value : null,
        };
    },

    // ===== 联系人 =====
    getContacts: function(limit, offset) {
        var db = getDB('main');
        limit = limit || 100; offset = offset || 0;
        return execSQL(db,
            "SELECT username, alias, conRemark, nickName, type, contactLabelIds, imgFlag " +
            "FROM rcontact WHERE type=3 AND verifyFlag=0 ORDER BY rowid LIMIT " + limit + " OFFSET " + offset
        );
    },

    getContactCount: function() {
        var db = getDB('main');
        var r1 = execSQL(db, "SELECT COUNT(*) as friends FROM rcontact WHERE type=3 AND verifyFlag=0");
        var r2 = execSQL(db, "SELECT COUNT(*) as total FROM rcontact");
        return {
            friends: r1.rows[0] ? r1.rows[0].friends : 0,
            total: r2.rows[0] ? r2.rows[0].total : 0
        };
    },

    getAllStats: function() {
        var db = getDB('main');
        var friends = execSQL(db, "SELECT COUNT(*) as n FROM rcontact WHERE type=3 AND verifyFlag=0");
        var groups = execSQL(db, "SELECT COUNT(*) as n FROM chatroom");
        var msgs = execSQL(db, "SELECT COUNT(*) as n FROM message");
        var imgs = execSQL(db, "SELECT COUNT(*) as n FROM ImgInfo2");
        var videos = execSQL(db, "SELECT COUNT(*) as n FROM videoinfo2");
        var conv = execSQL(db, "SELECT COUNT(*) as n FROM conversation");
        var files = execSQL(db, "SELECT COUNT(*) as n FROM FileMsgInfo");
        return {
            friends: friends.rows[0] ? parseInt(friends.rows[0].n) : 0,
            groups: groups.rows[0] ? parseInt(groups.rows[0].n) : 0,
            messages: msgs.rows[0] ? parseInt(msgs.rows[0].n) : 0,
            images: imgs.rows[0] ? parseInt(imgs.rows[0].n) : 0,
            videos: videos.rows[0] ? parseInt(videos.rows[0].n) : 0,
            conversations: conv.rows[0] ? parseInt(conv.rows[0].n) : 0,
            files: files.rows[0] ? parseInt(files.rows[0].n) : 0,
        };
    },

    searchContact: function(keyword) {
        var db = getDB('main');
        return execSQL(db,
            "SELECT username, alias, conRemark, nickName, type FROM rcontact " +
            "WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' OR alias LIKE '%" + keyword + "%') " +
            "AND type NOT IN (0,4) LIMIT 50"
        );
    },

    getContactDetail: function(wxid) {
        var db = getDB('main');
        return execSQL(db, "SELECT * FROM rcontact WHERE username='" + wxid + "' LIMIT 1");
    },

    // ===== 消息 =====
    getMessages: function(talker, limit) {
        var db = getDB('main');
        limit = limit || 50;
        return execSQL(db,
            "SELECT msgId, type, isSend, createTime, talker, content FROM message " +
            "WHERE talker='" + talker + "' ORDER BY createTime DESC LIMIT " + limit
        );
    },

    getRecentMessages: function(hours) {
        var db = getDB('main');
        hours = hours || 24;
        var since = Date.now() - hours * 3600 * 1000;
        return execSQL(db,
            "SELECT msgId, type, isSend, createTime, talker, content FROM message " +
            "WHERE createTime > " + since + " ORDER BY createTime DESC LIMIT 200"
        );
    },

    sendMessage: function(toUser, content) {
        var db = getDB('main');
        if (!db) return {error: 'main DB not available'};
        var msgId = Date.now();
        var createTime = Date.now();
        var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" +
            msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)";
        var result = writeSQL(db, sql);
        if (result.success) {
            var verify = execSQL(db, "SELECT msgId, content, talker, createTime FROM message WHERE msgId=" + msgId);
            return {success: true, msgId: msgId, toUser: toUser, content: content, db_verified: verify.count > 0, note: 'Written to local DB. Network sync requires real class name.'};
        }
        return result;
    },

    massMessage: function(targets, content) {
        var db = getDB('main');
        if (!db) return {error: 'main DB not available'};
        var results = [];
        targets.forEach(function(toUser) {
            var msgId = Date.now() + Math.floor(Math.random() * 100000);
            var createTime = Date.now();
            var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" +
                msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)";
            var r = writeSQL(db, sql);
            results.push({toUser: toUser, msgId: msgId, success: !!r.success, error: r.error || null});
        });
        return {results: results, total: targets.length, success_count: results.filter(function(r) { return r.success; }).length};
    },

    // ===== 会话 =====
    getConversations: function(limit) {
        var db = getDB('main');
        limit = limit || 30;
        return execSQL(db,
            "SELECT username, unReadCount, lastMsg, lastMsgCreateTime, isSend FROM conversation " +
            "ORDER BY lastMsgCreateTime DESC LIMIT " + limit
        );
    },

    // ===== 群组 =====
    getGroups: function(limit) {
        var db = getDB('main');
        limit = limit || 50;
        return execSQL(db,
            "SELECT chatroomname, memberlist, roomowner, announcement, selfDisplayName, memberCount " +
            "FROM chatroom ORDER BY rowid DESC LIMIT " + limit
        );
    },

    getGroupCount: function() {
        var db = getDB('main');
        return execSQL(db, "SELECT COUNT(*) as total FROM chatroom");
    },

    getGroupDetail: function(chatroomId) {
        var db = getDB('main');
        return execSQL(db, "SELECT * FROM chatroom WHERE chatroomname='" + chatroomId + "' LIMIT 1");
    },

    getGroupMembers: function(chatroomId) {
        var db = getDB('main');
        var group = execSQL(db, "SELECT memberlist, roomowner, announcement, selfDisplayName, memberCount FROM chatroom WHERE chatroomname='" + chatroomId + "'");
        if (group.rows && group.rows[0]) {
            var memberList = group.rows[0].memberlist || '';
            var members = memberList.split(';').filter(function(m) { return m.trim(); });
            return {
                chatroomId: chatroomId,
                members: members,
                count: members.length,
                owner: group.rows[0].roomowner,
                announcement: group.rows[0].announcement,
                myName: group.rows[0].selfDisplayName,
                memberCount: group.rows[0].memberCount
            };
        }
        return {error: 'Group not found'};
    },

    setGroupRemark: function(chatroomId, remark) {
        var db = getDB('main');
        return writeSQL(db, "UPDATE chatroom SET selfDisplayName='" + remark.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'");
    },

    setGroupAnnouncement: function(chatroomId, announcement) {
        var db = getDB('main');
        return writeSQL(db, "UPDATE chatroom SET announcement='" + announcement.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'");
    },

    // ===== 标签 =====
    getLabels: function() {
        var db = getDB('main');
        var r = execSQL(db, "SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds IS NOT NULL AND contactLabelIds != '' LIMIT 2000");
        var labelSet = {};
        if (r.rows) {
            r.rows.forEach(function(row) {
                var ids = (row.contactLabelIds || '').split(',');
                ids.forEach(function(id) { if (id.trim()) labelSet[id.trim()] = (labelSet[id.trim()] || 0) + 1; });
            });
        }
        return {label_ids: Object.keys(labelSet), count: Object.keys(labelSet).length, usage: labelSet};
    },

    getContactsByLabel: function(labelId) {
        var db = getDB('main');
        return execSQL(db,
            "SELECT username, nickName, conRemark, contactLabelIds FROM rcontact " +
            "WHERE contactLabelIds LIKE '%" + labelId + "%' AND type=3 LIMIT 100"
        );
    },

    // ===== 朋友圈 =====
    getSnsDbInfo: function() {
        initAllDBs();
        var result = {};
        ['sns','sns_star'].forEach(function(name) {
            var db = _dbs[name];
            if (db) {
                var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
                result[name] = {
                    available: true,
                    path: db.getPath(),
                    tables: tables.rows ? tables.rows.map(function(t) { return t.name; }) : []
                };
            } else {
                result[name] = {available: false};
            }
        });
        return result;
    },

    getMoments: function(limit) {
        limit = limit || 20;
        var db = getDB('sns');
        if (db) {
            var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
            var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
            if (tableNames.indexOf('SnsInfo') > -1) {
                var r = execSQL(db, "SELECT snsId, userName, createTime, content, type, localFlag FROM SnsInfo ORDER BY createTime DESC LIMIT " + limit);
                r.db = 'SnsMicroMsg';
                return r;
            }
        }
        var db2 = getDB('sns_star');
        if (db2) {
            var r2 = execSQL(db2, "SELECT * FROM StarSnsInfo ORDER BY createTime DESC LIMIT " + limit);
            r2.db = 'sns_star_info';
            return r2;
        }
        return {error: 'SNS DB not loaded. Need to open WeChat moments first.', rows: [], count: 0};
    },

    getMomentCount: function() {
        var db = getDB('sns');
        if (db) {
            var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
            var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
            if (tableNames.indexOf('SnsInfo') > -1) {
                return execSQL(db, "SELECT COUNT(*) as total FROM SnsInfo");
            }
        }
        var db2 = getDB('sns_star');
        if (db2) {
            return execSQL(db2, "SELECT COUNT(*) as total FROM StarSnsInfo");
        }
        return {error: 'SNS DB not loaded', count: 0};
    },

    postMoment: function(content) {
        var db = getDB('sns');
        if (db) {
            var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
            var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
            if (tableNames.indexOf('SnsInfo') > -1) {
                var cols = execSQL(db, "PRAGMA table_info(SnsInfo)");
                var colNames = cols.rows ? cols.rows.map(function(c) { return c.name; }) : [];
                var snsId = Date.now();
                var createTime = Math.floor(Date.now() / 1000);
                var insertCols = ['snsId', 'userName', 'createTime', 'content'];
                var insertVals = [snsId, "'wxid_5g37snchpv8e22'", createTime, "'" + content.replace(/'/g, "''") + "'"];
                if (colNames.indexOf('type') > -1) { insertCols.push('type'); insertVals.push(1); }
                if (colNames.indexOf('localFlag') > -1) { insertCols.push('localFlag'); insertVals.push(1); }
                var sql = "INSERT INTO SnsInfo (" + insertCols.join(',') + ") VALUES (" + insertVals.join(',') + ")";
                var r = writeSQL(db, sql);
                if (r.success) {
                    var verify = execSQL(db, "SELECT snsId, content FROM SnsInfo WHERE snsId=" + snsId);
                    return {success: true, snsId: snsId, content: content, db_verified: verify.count > 0, db: 'SnsMicroMsg'};
                }
                return r;
            }
        }
        var db2 = getDB('sns_star');
        if (db2) {
            var snsId2 = Date.now();
            var createTime2 = Math.floor(Date.now() / 1000);
            var sql2 = "INSERT INTO StarSnsInfo (snsId, userName, localFlag, createTime, content, type, localPrivate, likeFlag, pravited, stringSeq, withTa, withTaHasOther, sourceType, subType, serverExtFlag) VALUES (" +
                snsId2 + ", 'wxid_5g37snchpv8e22', 1, " + createTime2 + ", '" + content.replace(/'/g, "''") + "', 1, 0, 0, 0, '', 0, 0, 0, 0, 0)";
            var r2 = writeSQL(db2, sql2);
            if (r2.success) {
                var verify2 = execSQL(db2, "SELECT snsId, content FROM StarSnsInfo WHERE snsId=" + snsId2);
                return {success: true, snsId: snsId2, content: content, db_verified: verify2.count > 0, db: 'sns_star_info'};
            }
            return r2;
        }
        return {error: 'SNS DB not loaded. Open WeChat moments first.', success: false};
    },

    // ===== 视频号 =====
    getFinderInfo: function() {
        initAllDBs();
        var result = {};
        ['finder','finder2','finder3'].forEach(function(name) {
            var db = _dbs[name];
            if (db) {
                var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
                result[name] = {
                    available: true,
                    path: db.getPath().split('/').pop(),
                    tables: tables.rows ? tables.rows.map(function(t) { return t.name; }) : []
                };
            } else {
                result[name] = {available: false};
            }
        });
        return result;
    },

    getFinderContacts: function(limit) {
        var db = getDB('finder');
        limit = limit || 20;
        if (!db) return {error: 'FinderMM029 DB not available'};
        return execSQL(db, "SELECT * FROM FinderMsgContactStorage LIMIT " + limit);
    },

    getFinderMedia: function(limit) {
        var db = getDB('finder');
        limit = limit || 20;
        if (!db) return {error: 'FinderMM029 DB not available'};
        return execSQL(db, "SELECT * FROM FinderMediaCacheInfoV4 LIMIT " + limit);
    },

    getFinderAccounts: function() {
        var db = getDB('finder3');
        if (!db) return {error: 'FinderAccounts DB not available'};
        var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
        var result = {tables: tables.rows ? tables.rows.map(function(t) { return t.name; }) : []};
        (result.tables || []).forEach(function(t) {
            try { result[t] = execSQL(db, "SELECT * FROM " + t + " LIMIT 5"); } catch(e) {}
        });
        return result;
    },

    // ===== 收藏 =====
    getFavorites: function(limit) {
        limit = limit || 20;
        var db = getDB('favorite');
        if (db) {
            var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
            var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
            if (tableNames.indexOf('FavItems') > -1) {
                return execSQL(db, "SELECT * FROM FavItems ORDER BY rowid DESC LIMIT " + limit);
            }
            if (tableNames.length > 0) {
                return execSQL(db, "SELECT * FROM " + tableNames[0] + " LIMIT " + limit);
            }
        }
        // 尝试FTS5
        var db2 = getDB('fts5');
        if (db2) {
            var tables2 = execSQL(db2, "SELECT name FROM sqlite_master WHERE type='table'");
            var tableNames2 = tables2.rows ? tables2.rows.map(function(t) { return t.name; }) : [];
            if (tableNames2.indexOf('FTS5MetaFavorite') > -1) {
                return execSQL(db2, "SELECT * FROM FTS5MetaFavorite LIMIT " + limit);
            }
        }
        return {error: 'Favorite DB not loaded', rows: [], count: 0};
    },

    // ===== 钱包/红包 =====
    getWalletInfo: function() {
        var db = getDB('wallet');
        if (!db) return {error: 'WalletCoreDB not available'};
        var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
        var result = {tables: tables.rows ? tables.rows.map(function(t) { return t.name; }) : []};
        return result;
    },

    getWalletLedger: function(limit) {
        var db = getDB('wallet');
        limit = limit || 20;
        if (!db) return {error: 'Wallet DB not available'};
        return execSQL(db,
            "SELECT transferId, talker, msgTime, msgDate, tradeUser, tradeType, tradeAmount " +
            "FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT " + limit
        );
    },

    getLuckyMoney: function(limit) {
        var db = getDB('main');
        limit = limit || 20;
        return execSQL(db, "SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT " + limit);
    },

    getWalletUserInfo: function() {
        var db = getDB('wallet');
        if (!db) return {error: 'Wallet DB not available'};
        var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
        var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
        var result = {tables: tableNames};
        tableNames.forEach(function(t) {
            try {
                var r = execSQL(db, "SELECT * FROM " + t + " LIMIT 3");
                if (!r.error && r.count > 0) result[t] = r;
            } catch(e) {}
        });
        return result;
    },

    // ===== 图片/视频/文件 =====
    getImageList: function(limit) {
        var db = getDB('main');
        limit = limit || 20;
        return execSQL(db, "SELECT * FROM ImgInfo2 ORDER BY rowid DESC LIMIT " + limit);
    },

    getImageCount: function() {
        var db = getDB('main');
        return execSQL(db, "SELECT COUNT(*) as total FROM ImgInfo2");
    },

    getVideoList: function(limit) {
        var db = getDB('main');
        limit = limit || 20;
        return execSQL(db, "SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT " + limit);
    },

    getVideoCount: function() {
        var db = getDB('main');
        return execSQL(db, "SELECT COUNT(*) as total FROM videoinfo2");
    },

    getFileList: function(limit) {
        var db = getDB('main');
        limit = limit || 20;
        return execSQL(db, "SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT " + limit);
    },

    // ===== 小程序 =====
    getAppBrandList: function() {
        var db = getDB('appbrand');
        if (!db) return {error: 'AppBrand DB not available'};
        var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
        var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
        var result = {tables: tableNames};
        tableNames.slice(0, 5).forEach(function(t) {
            try {
                var r = execSQL(db, "SELECT * FROM " + t + " LIMIT 5");
                if (!r.error) result[t] = r;
            } catch(e) {}
        });
        return result;
    },

    // ===== 搜索 =====
    globalSearch: function(keyword) {
        var db = getDB('main');
        var contacts = execSQL(db, "SELECT username, nickName, conRemark FROM rcontact WHERE nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' LIMIT 10");
        var messages = execSQL(db, "SELECT talker, content, createTime FROM message WHERE content LIKE '%" + keyword + "%' ORDER BY createTime DESC LIMIT 10");
        var groups = execSQL(db, "SELECT chatroomname FROM chatroom WHERE chatroomname LIKE '%" + keyword + "%' LIMIT 10");
        return {contacts: contacts, messages: messages, groups: groups};
    },

    // ===== 原始SQL =====
    rawQuery: function(dbName, sql) {
        var db = getDB(dbName || 'main');
        return execSQL(db, sql);
    },

    rawWrite: function(dbName, sql) {
        var db = getDB(dbName || 'main');
        return writeSQL(db, sql);
    },

    getTableInfo: function(dbName, tableName) {
        var db = getDB(dbName || 'main');
        var cols = execSQL(db, "PRAGMA table_info(" + tableName + ")");
        var count = execSQL(db, "SELECT COUNT(*) as total FROM " + tableName);
        var sample = execSQL(db, "SELECT * FROM " + tableName + " LIMIT 3");
        return {columns: cols, count: count, sample: sample};
    },

    listTables: function(dbName) {
        var db = getDB(dbName || 'main');
        return execSQL(db, "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
    },
};

// 启动时初始化
Java.perform(function() {
    initAllDBs();
    console.log('[*] WeChat SDK v8-fix loaded. DBs found: ' + Object.keys(_dbs).length);
});
