/**
 * wechat_hook_ckb_patch.js — 存客宝专项 Hook 扩展补丁
 *
 * 在 wechat_hook_v2.js 基础上，新增以下功能（F-CKB-1 ~ F-CKB-3）：
 *
 *   F-CKB-1  getContactsDetail    — 获取联系人详细信息（标签/手机号/性别/地区/备注）
 *   F-CKB-2  getGroupMembersDetail — 获取群成员详细信息（含每个成员的联系人信息）
 *   F-CKB-3  onFriendAdd          — 新好友添加事件监听（实时上报到 SDK 服务端）
 *   F-CKB-3  onGroupMemberJoin    — 群成员加入事件监听（实时上报到 SDK 服务端）
 *   F-CKB-4  batchSyncContacts    — 批量同步通讯录到存客宝（含分批上报）
 *
 * 使用方式：
 *   此文件作为独立补丁脚本，与 wechat_hook_v2.js 一起注入，
 *   或将以下函数合并到 wechat_hook_v2.js 的对应位置。
 *
 * @version 1.0.0 (CKB专项)
 * @date 2026-05-15
 */
'use strict';

// ============================================================
// § CKB-1  联系人详细信息获取（扩展版）
// ============================================================

/**
 * 获取联系人详细信息（包含存客宝所需的全部字段）
 *
 * 数据来源：
 *   - rcontact 表：基础信息（wxid/nickname/remark/type/alias）
 *   - contactlabelinfo 表：标签信息
 *   - bizinfo 表：手机号（部分版本）
 *
 * @param {number} limit - 最大返回数量，默认 500
 * @returns {{ success: boolean, contacts: Array, count: number }}
 */
function _getContactsDetailFromDB(limit) {
    limit = limit || 500;

    // Step 1: 获取基础联系人信息（扩展字段）
    var sql = "SELECT username, nickname, conRemark, type, alias, "
        + "imgFlag, sex, country, province, city, signature "
        + "FROM rcontact "
        + "WHERE type NOT IN (0, 33) AND verifyFlag=0 "
        + "AND username NOT LIKE '%@chatroom' "
        + "AND username NOT LIKE 'gh_%' "
        + "ORDER BY nickname LIMIT " + limit;

    var rows = _execSQL(sql);

    // Step 2: 获取标签映射
    var labelMap = {};
    try {
        var labelSql = "SELECT labelId, labelName FROM contactlabelinfo";
        var labelRows = _execSQL(labelSql);
        labelRows.forEach(function(r) {
            labelMap[r.labelId] = r.labelName;
        });
    } catch(e) {
        // 部分版本无此表，忽略
    }

    // Step 3: 获取联系人标签关联
    var contactLabelMap = {};
    try {
        var clSql = "SELECT username, labelidlist FROM rcontact WHERE labelidlist IS NOT NULL AND labelidlist != ''";
        var clRows = _execSQL(clSql);
        clRows.forEach(function(r) {
            if (r.labelidlist) {
                var ids = r.labelidlist.split(',').filter(function(id) { return id; });
                var names = ids.map(function(id) { return labelMap[id] || id; }).filter(function(n) { return n; });
                contactLabelMap[r.username] = names;
            }
        });
    } catch(e) {
        // 忽略
    }

    // Step 4: 组装详细联系人信息
    var contacts = rows.map(function(r) {
        var sexMap = { '0': 'unknown', '1': 'male', '2': 'female' };
        return {
            wxid: r.username || '',
            nickname: r.nickname || '',
            remark: r.conRemark || '',
            alias: r.alias || '',          // 微信号（字母ID）
            type: r.type || 0,
            sex: sexMap[String(r.sex)] || 'unknown',
            country: r.country || '',
            province: r.province || '',
            city: r.city || '',
            signature: r.signature || '',   // 个性签名
            tags: contactLabelMap[r.username] || [],  // 标签列表
            has_avatar: (r.imgFlag || 0) > 0,
        };
    });

    return { success: true, contacts: contacts, count: contacts.length };
}

/**
 * 获取单个联系人的详细信息
 *
 * @param {string} wxid - 微信号
 * @returns {{ success: boolean, contact: Object }}
 */
function _getContactDetailFromDB(wxid) {
    if (!wxid) return { success: false, error: '缺少 wxid' };

    var sql = "SELECT username, nickname, conRemark, type, alias, "
        + "imgFlag, sex, country, province, city, signature "
        + "FROM rcontact WHERE username='" + wxid.replace(/'/g, "''") + "'";

    var rows = _execSQL(sql);
    if (rows.length === 0) return { success: false, error: '未找到联系人: ' + wxid };

    var r = rows[0];

    // 获取标签
    var tags = [];
    try {
        var labelSql = "SELECT labelidlist FROM rcontact WHERE username='" + wxid.replace(/'/g, "''") + "'";
        var lRows = _execSQL(labelSql);
        if (lRows.length > 0 && lRows[0].labelidlist) {
            var labelMapSql = "SELECT labelId, labelName FROM contactlabelinfo";
            var lmRows = _execSQL(labelMapSql);
            var lm = {};
            lmRows.forEach(function(lr) { lm[lr.labelId] = lr.labelName; });
            tags = lRows[0].labelidlist.split(',')
                .filter(function(id) { return id; })
                .map(function(id) { return lm[id] || id; });
        }
    } catch(e) {}

    var sexMap = { '0': 'unknown', '1': 'male', '2': 'female' };
    return {
        success: true,
        contact: {
            wxid: r.username || '',
            nickname: r.nickname || '',
            remark: r.conRemark || '',
            alias: r.alias || '',
            type: r.type || 0,
            sex: sexMap[String(r.sex)] || 'unknown',
            country: r.country || '',
            province: r.province || '',
            city: r.city || '',
            signature: r.signature || '',
            tags: tags,
            has_avatar: (r.imgFlag || 0) > 0,
        }
    };
}


// ============================================================
// § CKB-2  群成员详细信息获取（扩展版）
// ============================================================

/**
 * 获取群成员详细信息（含每个成员的联系人信息）
 *
 * @param {string} groupId - 群ID（chatroomname）
 * @returns {{ success: boolean, group_id: string, members: Array, count: number }}
 */
function _getGroupMembersDetailFromDB(groupId) {
    if (!groupId) return { success: false, error: '缺少 group_id', members: [] };

    // Step 1: 获取群成员列表
    var sql = "SELECT memberlist, displayname, roomowner, chatroomnick FROM chatroom"
        + " WHERE chatroomname='" + groupId.replace(/'/g, "''") + "'";
    var rows = _execSQL(sql);
    if (rows.length === 0) return { success: false, error: '群不存在: ' + groupId, members: [] };

    var r = rows[0];
    var memberWxids = (r.memberlist || '').split(';').filter(function(m) { return m.trim(); });
    var displayNames = (r.displayname || '').split(';');
    var owner = r.roomowner || '';

    if (memberWxids.length === 0) {
        return { success: true, group_id: groupId, group_name: r.chatroomnick || '', members: [], count: 0 };
    }

    // Step 2: 批量获取成员联系人信息（分批查询，每批50个）
    var memberInfoMap = {};
    var batchSize = 50;
    for (var i = 0; i < memberWxids.length; i += batchSize) {
        var batch = memberWxids.slice(i, i + batchSize);
        var inClause = batch.map(function(id) { return "'" + id.replace(/'/g, "''") + "'"; }).join(',');
        try {
            var infoSql = "SELECT username, nickname, conRemark, alias, sex, country, province, city "
                + "FROM rcontact WHERE username IN (" + inClause + ")";
            var infoRows = _execSQL(infoSql);
            infoRows.forEach(function(ir) {
                memberInfoMap[ir.username] = ir;
            });
        } catch(e) {}
    }

    // Step 3: 组装成员详细信息
    var sexMap = { '0': 'unknown', '1': 'male', '2': 'female' };
    var members = memberWxids.map(function(wxid, idx) {
        var info = memberInfoMap[wxid] || {};
        return {
            wxid: wxid,
            display_name: (displayNames[idx] || '').trim(),
            nickname: info.nickname || '',
            remark: info.conRemark || '',
            alias: info.alias || '',
            sex: sexMap[String(info.sex)] || 'unknown',
            country: info.country || '',
            province: info.province || '',
            city: info.city || '',
            is_owner: wxid === owner,
            in_contacts: !!info.nickname,  // 是否在通讯录中
        };
    });

    return {
        success: true,
        group_id: groupId,
        group_name: r.chatroomnick || '',
        owner: owner,
        members: members,
        count: members.length,
    };
}


// ============================================================
// § CKB-3  实时事件监听（新好友 / 群成员加入）
// ============================================================

/**
 * 启动新好友添加事件监听
 * 通过 SQLite insert Hook 监听 rcontact 表的新增记录
 *
 * 触发条件：verifyFlag=0 且 type=3（好友类型）的新记录
 */
function _startFriendAddListener() {
    try {
        // 监听 SQLite insert，过滤 rcontact 表的新好友
        // 此函数需要在 Java.perform 上下文中调用
        Java.perform(function() {
            var SQLiteDatabase = Java.use('android.database.sqlite.SQLiteDatabase');

            SQLiteDatabase.insert.overload(
                'java.lang.String',
                'java.lang.String',
                'android.content.ContentValues'
            ).implementation = function(table, nullColumnHack, values) {
                var result = this.insert(table, nullColumnHack, values);

                if (table === 'rcontact') {
                    try {
                        var wxid = '';
                        var nickname = '';
                        var type = 0;
                        var verifyFlag = 0;

                        // 从 ContentValues 读取字段
                        if (values) {
                            try { wxid = values.getAsString('username') || ''; } catch(e) {}
                            try { nickname = values.getAsString('nickname') || ''; } catch(e) {}
                            try { type = parseInt(values.getAsInteger('type') || 0); } catch(e) {}
                            try { verifyFlag = parseInt(values.getAsInteger('verifyFlag') || 0); } catch(e) {}
                        }

                        // 新好友条件：type=3（普通好友）且 verifyFlag=0（已通过验证）
                        if (type === 3 && verifyFlag === 0 && wxid) {
                            emitEvent('friend_add', {
                                wxid: wxid,
                                nickname: nickname,
                                source: '微信添加',
                                timestamp: Date.now(),
                                // 标记需要上报到存客宝
                                report_to_ckb: true,
                            });
                            log('info', 'ckb', '新好友添加事件: ' + wxid + ' (' + nickname + ')');
                        }
                    } catch(e) {
                        log('warn', 'ckb', '解析新好友事件失败: ' + e);
                    }
                }

                return result;
            };

            log('info', 'ckb', '新好友添加监听已启动');
        });
        return { success: true };
    } catch(e) {
        log('warn', 'ckb', '启动新好友监听失败: ' + e);
        return { success: false, error: String(e) };
    }
}

/**
 * 启动群成员加入事件监听
 * 通过监听 chatroom 表的 memberlist 字段变化来检测新成员
 */
function _startGroupMemberJoinListener() {
    // 缓存已知群成员，用于对比变化
    var _groupMemberCache = {};

    try {
        Java.perform(function() {
            var SQLiteDatabase = Java.use('android.database.sqlite.SQLiteDatabase');

            SQLiteDatabase.update.overload(
                'java.lang.String',
                'android.content.ContentValues',
                'java.lang.String',
                '[Ljava.lang.String;'
            ).implementation = function(table, values, whereClause, whereArgs) {
                var result = this.update(table, values, whereClause, whereArgs);

                if (table === 'chatroom') {
                    try {
                        var groupId = '';
                        var newMemberList = '';

                        if (values) {
                            try { newMemberList = values.getAsString('memberlist') || ''; } catch(e) {}
                        }
                        // 从 whereClause 提取群ID
                        if (whereClause && whereClause.indexOf('chatroomname') !== -1 && whereArgs && whereArgs.length > 0) {
                            groupId = whereArgs[0] || '';
                        }

                        if (groupId && newMemberList) {
                            var newMembers = newMemberList.split(';').filter(function(m) { return m.trim(); });
                            var oldMembers = _groupMemberCache[groupId] || [];

                            // 找出新加入的成员
                            var joinedMembers = newMembers.filter(function(m) {
                                return oldMembers.indexOf(m) === -1;
                            });

                            if (joinedMembers.length > 0) {
                                joinedMembers.forEach(function(wxid) {
                                    emitEvent('group_member_join', {
                                        group_id: groupId,
                                        wxid: wxid,
                                        timestamp: Date.now(),
                                        report_to_ckb: true,
                                    });
                                    log('info', 'ckb', '群成员加入: ' + wxid + ' -> ' + groupId);
                                });
                            }

                            // 更新缓存
                            _groupMemberCache[groupId] = newMembers;
                        }
                    } catch(e) {
                        log('warn', 'ckb', '解析群成员变动失败: ' + e);
                    }
                }

                return result;
            };

            log('info', 'ckb', '群成员加入监听已启动');
        });
        return { success: true };
    } catch(e) {
        log('warn', 'ckb', '启动群成员监听失败: ' + e);
        return { success: false, error: String(e) };
    }
}


// ============================================================
// § CKB-4  批量同步通讯录到存客宝
// ============================================================

/**
 * 批量同步通讯录到存客宝
 * 获取全部联系人详细信息，通过 HTTP 上报到 SDK 服务端
 *
 * @param {Object} params
 * @param {string} params.server_url - SDK 服务端地址（如 http://192.168.1.100:8899）
 * @param {string} params.device_id  - 设备ID
 * @param {number} params.limit      - 最大同步数量，默认 500
 * @param {number} params.batch_size - 每批上报数量，默认 50
 */
function _batchSyncContactsToCKB(params) {
    var serverUrl = (params && params.server_url) || '';
    var deviceId = (params && params.device_id) || '';
    var limit = (params && params.limit) || 500;
    var batchSize = (params && params.batch_size) || 50;

    if (!serverUrl || !deviceId) {
        return { success: false, error: '缺少 server_url 或 device_id' };
    }

    try {
        // 获取联系人详细信息
        var result = _getContactsDetailFromDB(limit);
        if (!result.success || result.contacts.length === 0) {
            return { success: false, error: '获取联系人失败或为空' };
        }

        var contacts = result.contacts;
        var totalBatches = Math.ceil(contacts.length / batchSize);
        var successCount = 0;
        var failCount = 0;

        log('info', 'ckb', '开始批量同步通讯录: ' + contacts.length + ' 个联系人，共 ' + totalBatches + ' 批');

        // 使用 Java HTTP 客户端发送请求
        Java.perform(function() {
            var URL = Java.use('java.net.URL');
            var HttpURLConnection = Java.use('java.net.HttpURLConnection');
            var BufferedReader = Java.use('java.io.BufferedReader');
            var InputStreamReader = Java.use('java.io.InputStreamReader');
            var OutputStreamWriter = Java.use('java.io.OutputStreamWriter');
            var JSONObject = Java.use('org.json.JSONObject');
            var JSONArray = Java.use('org.json.JSONArray');

            for (var i = 0; i < contacts.length; i += batchSize) {
                var batch = contacts.slice(i, i + batchSize);
                var batchNum = Math.floor(i / batchSize) + 1;

                try {
                    var url = new URL(serverUrl + '/api/v3/cunke-bao/batch-contacts');
                    var conn = url.openConnection();
                    conn.setRequestMethod('POST');
                    conn.setRequestProperty('Content-Type', 'application/json');
                    conn.setDoOutput(true);
                    conn.setConnectTimeout(10000);
                    conn.setReadTimeout(15000);

                    // 构建请求体
                    var bodyObj = {
                        device_id: deviceId,
                        source: '微信通讯录同步',
                        contacts: batch
                    };
                    var bodyStr = JSON.stringify(bodyObj);

                    var writer = new OutputStreamWriter(conn.getOutputStream());
                    writer.write(bodyStr);
                    writer.flush();
                    writer.close();

                    var responseCode = conn.getResponseCode();
                    if (responseCode === 200) {
                        successCount += batch.length;
                        log('info', 'ckb', '批次 ' + batchNum + '/' + totalBatches + ' 上报成功');
                    } else {
                        failCount += batch.length;
                        log('warn', 'ckb', '批次 ' + batchNum + ' 上报失败，HTTP ' + responseCode);
                    }
                    conn.disconnect();
                } catch(batchErr) {
                    failCount += batch.length;
                    log('error', 'ckb', '批次 ' + batchNum + ' 异常: ' + batchErr);
                }

                // 批次间延迟 200ms，避免服务端压力
                java.lang.Thread.sleep(200);
            }
        });

        return {
            success: true,
            total: contacts.length,
            success_count: successCount,
            fail_count: failCount,
        };
    } catch(e) {
        return { success: false, error: String(e) };
    }
}


// ============================================================
// § CKB  rpc.exports 扩展（追加到现有 rpc.exports 对象）
// ============================================================

/**
 * 将以下方法追加到 wechat_hook_v2.js 的 rpc.exports 对象中：
 *
 * getContactsDetail:       获取联系人详细信息（含标签/性别/地区）
 * getContactDetail:        获取单个联系人详细信息
 * getGroupMembersDetail:   获取群成员详细信息（含联系人信息）
 * startFriendAddListener:  启动新好友添加事件监听
 * startGroupMemberListener: 启动群成员加入事件监听
 * batchSyncContacts:       批量同步通讯录到存客宝
 */
var _ckbExports = {
    // F-CKB-1: 获取联系人详细信息
    getContactsDetail: function(params) {
        var limit = (params && params.limit) || 500;
        try {
            return Java.performNow(function() { return _getContactsDetailFromDB(limit); });
        } catch(e) {
            return { success: false, error: String(e), contacts: [] };
        }
    },

    // F-CKB-1: 获取单个联系人详细信息
    getContactDetail: function(params) {
        var wxid = (params && params.wxid) || '';
        if (!wxid) return { success: false, error: '缺少 wxid' };
        try {
            return Java.performNow(function() { return _getContactDetailFromDB(wxid); });
        } catch(e) {
            return { success: false, error: String(e) };
        }
    },

    // F-CKB-2: 获取群成员详细信息
    getGroupMembersDetail: function(params) {
        var groupId = (params && params.group_id) || '';
        if (!groupId) return { success: false, error: '缺少 group_id' };
        try {
            return Java.performNow(function() { return _getGroupMembersDetailFromDB(groupId); });
        } catch(e) {
            return { success: false, error: String(e), members: [] };
        }
    },

    // F-CKB-3: 启动新好友添加事件监听
    startFriendAddListener: function() {
        return _startFriendAddListener();
    },

    // F-CKB-3: 启动群成员加入事件监听
    startGroupMemberListener: function() {
        return _startGroupMemberJoinListener();
    },

    // F-CKB-4: 批量同步通讯录到存客宝
    batchSyncContacts: function(params) {
        try {
            return Java.performNow(function() { return _batchSyncContactsToCKB(params); });
        } catch(e) {
            return { success: false, error: String(e) };
        }
    },
};

// 将 CKB 扩展方法合并到 rpc.exports
// （此行需要在 wechat_hook_v2.js 的 rpc.exports 定义之后执行）
if (typeof rpc !== 'undefined' && rpc.exports) {
    Object.assign(rpc.exports, _ckbExports);
    log('info', 'ckb', 'CKB 扩展 Hook 已注入: getContactsDetail/getGroupMembersDetail/startFriendAddListener/startGroupMemberListener/batchSyncContacts');
}
