package im.zego;

import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import im.zego.zim.entity.*;
import im.zego.zim.enums.*;
import im.zego.zim.event.*;
import java.lang.Integer;
import java.lang.System;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;

public class RNZIMConverter {

    public static ReadableArray mStringArray(ArrayList<String> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (String key : infos) {
            array.pushString(key);
        }

        return array;
    }

    public static ArrayList<String> oStringArray(ReadableArray infos) {
        ArrayList<String> array = new ArrayList<>();
        for (Object key : infos.toArrayList()) {
            array.add((String) key);
        }

        return array;
    }

    public static ReadableArray mIntArray(ArrayList<Integer> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (int key : infos) {
            array.pushInt(key);
        }

        return array;
    }

    public static ArrayList<Integer> oIntArray(ReadableArray infos) {
        ArrayList<Integer> array = new ArrayList<>();
        for (Object key : infos.toArrayList()) {
            array.add(Double.valueOf((double) key).intValue());
        }

        return array;
    }

    public static ArrayList<ZIMConversationType> oZIMConversationTypeArray(ReadableArray infos) {
        ArrayList<ZIMConversationType> array = new ArrayList<>();
        for (Object key : infos.toArrayList()) {
            array.add(ZIMConversationType.getZIMConversationType(Double.valueOf((double) key).intValue()));
        }

        return array;
    }

    public static ArrayList<ZIMMessageType> oZIMMessageTypeArray(ReadableArray infos) {
        ArrayList<ZIMMessageType> array = new ArrayList<>();
        for (Object key : infos.toArrayList()) {
            array.add(ZIMMessageType.getZIMMessageType(Double.valueOf((double) key).intValue()));
        }

        return array;
    }

    public static ReadableMap mMap(HashMap<String, String> map) {
        if (map == null) {
            return null;
        }

        WritableMap res = Arguments.createMap();
        for (String key : map.keySet()) {
            res.putString(key, map.get(key));
        }

        return res;
    }

    public static HashMap<String, String> oMap(ReadableMap map) {
        HashMap<String, String> res = new HashMap<>();

        if (map != null) {
            HashMap<String, Object> _map = map.toHashMap();
            for (String key : _map.keySet()) {
                res.put(key, (String) _map.get(key));
            }
        }

        return res;
    }

    public static ZIMPushConfig oZIMPushConfig(ReadableMap config) {
        if (config.hasKey("pushConfig")) {
            ReadableMap pushMap = config.getMap("pushConfig");
            ZIMPushConfig pushConfig = new ZIMPushConfig();
            pushConfig.title = pushMap.hasKey("title") ? pushMap.getString("title") : "";
            pushConfig.content = pushMap.hasKey("content") ? pushMap.getString("content") : "";
            pushConfig.payload = pushMap.hasKey("payload") ? pushMap.getString("payload") : "";
            pushConfig.resourcesID = pushMap.hasKey("resourcesID") ? pushMap.getString("resourcesID") : "";
            pushConfig.threadID = pushMap.hasKey("threadID") ? pushMap.getString("threadID") : "";
            pushConfig.badgeIncrement = pushMap.hasKey("badgeIncrement") ? pushMap.getInt("badgeIncrement") : 0;
            pushConfig.enableBadge = pushMap.hasKey("enableBadge") ? pushMap.getBoolean("enableBadge") : false;
            if (pushMap.getMap("voIPConfig") != null) {
                ReadableMap map = pushMap.getMap("voIPConfig");
                ZIMVoIPConfig voIPConfig = new ZIMVoIPConfig();
                voIPConfig.iOSVoIPHandleType = ZIMCXHandleType.getZIMCXHandleType(map.getInt("iOSVoIPHandleType"));
                voIPConfig.iOSVoIPHandleValue = map.hasKey("iOSVoIPHandleValue")
                    ? map.getString("iOSVoIPHandleValue")
                    : "";
                voIPConfig.iOSVoIPHasVideo = map.hasKey("iOSVoIPHasVideo") ? map.getBoolean("iOSVoIPHasVideo") : false;
                pushConfig.voIPConfig = voIPConfig;
            }
            if (pushMap.getMap("privateMessageTemplate") != null) {
                ReadableMap map = pushMap.getMap("privateMessageTemplate");
                ZIMOfflinePushPrivateMessageTemplate tempConfig = new ZIMOfflinePushPrivateMessageTemplate();
                tempConfig.templateID = map.hasKey("templateID") ? map.getString("templateID") : "";
                tempConfig.titleParameters = map.hasKey("titleParameters") ? map.getString("titleParameters") : "";
                tempConfig.contentParameters = map.hasKey("contentParameters")
                    ? map.getString("contentParameters")
                    : "";
                pushConfig.privateMessageTemplate = tempConfig;
            }
            return pushConfig;
        }
        return null;
    }

    public static ReadableMap mZIMMessageReceivedInfo(ZIMMessageReceivedInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putBoolean("isOfflineMessage", info.isOfflineMessage);
        map.putString("conversationID", info.conversationID);
        map.putInt("conversationType", info.conversationType.value());

        return map;
    }

    public static ReadableMap mZIMUserInfo(ZIMUserInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        return map;
    }

    public static ReadableArray mZIMUserInfoList(ArrayList<ZIMUserInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMUserInfo info : infos) {
            array.pushMap(mZIMUserInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMUserFullInfo(ZIMUserFullInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMUserInfo(info.baseInfo));

        return map;
    }

    public static ReadableMap mZIMUserOfflinePushRule(ZIMUserOfflinePushRule info) {
        if (info == null) {
            return null;
        }

        WritableMap ruleMap = Arguments.createMap();
        ruleMap.putArray("onlinePlatforms", mIntArray(info.onlinePlatforms));
        ruleMap.putArray("notToReceiveOfflinePushPlatforms", mIntArray(info.notToReceiveOfflinePushPlatforms));

        WritableMap map = Arguments.createMap();
        map.putMap("offlinePushRule", ruleMap);
        return map;
    }

    public static ReadableMap mZIMUserStatus(ZIMUserStatus info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("userID", info.userID);
        map.putString("customStatus", info.customStatus);
        map.putInt("onlineStatus", info.onlineStatus.value());
        map.putDouble("lastUpdateTime", info.lastUpdateTime);
        map.putDouble("lastOnlineStatusUpdateTime", info.lastOnlineStatusUpdateTime);
        map.putDouble("lastCustomStatusUpdateTime", info.lastCustomStatusUpdateTime);

        WritableArray onlineArray = Arguments.createArray();
        for (ZIMPlatformType item : info.onlinePlatforms) {
            onlineArray.pushInt(item.value());
        }
        map.putArray("onlinePlatforms", onlineArray);

        return map;
    }

    public static ReadableArray mZIMUserStatusList(ArrayList<ZIMUserStatus> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMUserStatus info : infos) {
            array.pushMap(mZIMUserStatus(info));
        }

        return array;
    }

    public static ReadableArray mZIMErrorUserInfo(ArrayList<ZIMErrorUserInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMErrorUserInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putString("userID", info.userID);
            map.putInt("reason", info.reason);
            array.pushMap(map);
        }

        return array;
    }

    public static ReadableMap mZIMRoomMemberInfo(ZIMRoomMemberInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        return map;
    }

    public static ReadableMap mZIMConversation(ZIMConversation info) {
        if (info == null) {
            return null;
        }

        int type = info.type.value();

        WritableMap map = Arguments.createMap();
        map.putString("conversationID", info.conversationID);
        map.putString("conversationName", info.conversationName);
        map.putString("conversationAlias", info.conversationAlias);
        map.putString("conversationAvatarUrl", info.conversationAvatarUrl);
        map.putInt("type", type);
        map.putInt("unreadMessageCount", info.unreadMessageCount);
        map.putDouble("orderKey", info.orderKey);
        map.putDouble("readMessageSeq", info.readMessageSeq);
        map.putInt("notificationStatus", info.notificationStatus.value());
        map.putBoolean("isPinned", info.isPinned);
        map.putDouble("pinnedTime", info.pinnedTime);
        map.putString("draft", info.draft);
        map.putInt("messageDestructDuration", info.messageDestructDuration);
        if (info.lastMessage != null) {
            map.putMap("lastMessage", mZIMMessage(info.lastMessage));
        } else {
            map.putNull("lastMessage");
        }
        if (info.mentionedInfoList != null) {
            map.putArray("mentionedInfoList", mZIMMessageMentionedInfoList(info.mentionedInfoList));
        }
        if (info.marks != null) {
            map.putArray("marks", mIntArray(info.marks));
        }

        map.putBoolean("isConversationDisabled", info.isConversationDisabled);
        map.putDouble("selfMutedExpiredTime", info.selfMutedExpiredTime);
        if (type == 2) {
            map.putBoolean("isDisabled", info.isConversationDisabled);
            map.putDouble("mutedExpiredTime", info.selfMutedExpiredTime);
        }

        return map;
    }

    public static ZIMConversation oZIMConversation(ReadableMap map) {
        if (map == null) {
            return null;
        }

        ZIMConversation info = new ZIMConversation();
        info.conversationID = map.hasKey("conversationID") ? map.getString("conversationID") : "";
        info.conversationName = map.hasKey("conversationName") ? map.getString("conversationName") : "";
        info.conversationAlias = map.hasKey("conversationAlias") ? map.getString("conversationAlias") : "";
        info.conversationAvatarUrl = map.hasKey("conversationAvatarUrl") ? map.getString("conversationAvatarUrl") : "";
        info.unreadMessageCount = map.hasKey("unreadMessageCount") ? map.getInt("unreadMessageCount") : 0;
        info.messageDestructDuration = map.hasKey("messageDestructDuration") ? map.getInt("messageDestructDuration") : 0;
        long orderKey = map.hasKey("orderKey") ? Double.valueOf(map.getDouble("orderKey")).longValue() : 0;
        info.orderKey = orderKey;
        long readMessageSeq = map.hasKey("readMessageSeq")
            ? Double.valueOf(map.getDouble("readMessageSeq")).longValue()
            : 0;
        info.readMessageSeq = readMessageSeq;
        info.type = ZIMConversationType.getZIMConversationType(map.getInt("type"));
        info.notificationStatus = ZIMConversationNotificationStatus.getZIMConversationNotificationStatus(
            map.getInt("notificationStatus")
        );
        info.isPinned = map.hasKey("isPinned") ? map.getBoolean("isPinned") : false;
        long pinnedTime = map.hasKey("pinnedTime") ? Double.valueOf(map.getDouble("pinnedTime")).longValue() : 0;
        info.pinnedTime = pinnedTime;
        info.draft = map.hasKey("draft") ? map.getString("draft") : "";
        info.lastMessage = null;

        return info;
    }

    public static ReadableArray mZIMConversationList(ArrayList<ZIMConversation> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMConversation info : infos) {
            array.pushMap(mZIMConversation(info));
        }

        return array;
    }

    public static ReadableArray mZIMMessageMentionedInfoList(ArrayList<ZIMMessageMentionedInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMMessageMentionedInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putInt("type", info.type.value());
            map.putString("fromUserID", info.fromUserID);
            map.putString("messageID", String.valueOf(info.messageID));
            map.putDouble("messageSeq", info.messageSeq);
            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMMessageReceiptInfo(ArrayList<ZIMMessageReceiptInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMMessageReceiptInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putString("conversationID", info.conversationID);
            map.putInt("conversationType", info.conversationType.value());
            map.putString("messageID", String.valueOf(info.messageID));
            map.putInt("status", info.status.value());
            map.putInt("readMemberCount", info.readMemberCount);
            map.putInt("unreadMemberCount", info.unreadMemberCount);
            map.putInt("deliveredMemberCount", info.deliveredMemberCount);
            map.putBoolean("isSelfOperated", info.isSelfOperated);
            map.putDouble("readTime", info.readTime);

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableMap mZIMMessageReaction(ZIMMessageReaction info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("conversationID", info.conversationID);
        map.putInt("conversationType", info.conversationType.value());
        map.putString("messageID", String.valueOf(info.messageID));
        map.putString("reactionType", info.reactionType);
        map.putInt("totalCount", info.totalCount);
        map.putInt("sumCount", info.sumCount);
        map.putBoolean("isSelfIncluded", info.isSelfIncluded);

        WritableArray userArray = Arguments.createArray();
        for (ZIMMessageReactionUserInfo user : info.userList) {
            WritableMap userMap = Arguments.createMap();
            userMap.putString("userID", user.userID);
            userArray.pushMap(userMap);
        }
        map.putArray("userList", userArray);

        return map;
    }

    public static ReadableArray mZIMMessageReactionList(ArrayList<ZIMMessageReaction> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMMessageReaction info : infos) {
            array.pushMap(mZIMMessageReaction(info));
        }

        return array;
    }

    public static ReadableMap mZIMMessageSentStatusChangeInfo(ZIMMessageSentStatusChangeInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("reason", info.reason);
        map.putInt("status", info.status.value());
        map.putMap("message", mZIMMessage(info.message));

        return map;
    }

    // Used for incoming base message
    public static ZIMMessage oZIMMessage(ReadableMap messageMap) {
        if (messageMap == null) {
            return null;
        }

        ZIMMessage message = null;
        ZIMMessageType type = ZIMMessageType.getZIMMessageType(messageMap.getInt("type"));
        switch (type) {
            case TEXT:
                String textContent = messageMap.hasKey("message") ? messageMap.getString("message") : "";
                message = new ZIMTextMessage(textContent);
                break;
            case COMMAND:
                ReadableArray byteArr = messageMap.getArray("message");
                int size = byteArr.size();
                byte[] bytes = new byte[size];
                for (int i = 0; i < size; i++) {
                    int b = Double.valueOf(byteArr.getDouble(i)).intValue();
                    bytes[i] = (byte) (b < 128 ? b : b - 256);
                }
                message = new ZIMCommandMessage(bytes);
                break;
            case BARRAGE:
                String barrageContent = messageMap.hasKey("message") ? messageMap.getString("message") : "";
                message = new ZIMBarrageMessage(barrageContent);
                break;
            case REVOKE:
                message = new ZIMRevokeMessage();
                try {
                    Field revokeTypeField = ZIMRevokeMessage.class.getDeclaredField("revokeType");
                    revokeTypeField.setAccessible(true);
                    int revokeType = messageMap.hasKey("revokeType") ? messageMap.getInt("revokeType") : -1;
                    revokeTypeField.set(message, ZIMRevokeType.getZIMRevokeType(revokeType));
                    revokeTypeField.setAccessible(false);

                    Field originalMessageTypeField = ZIMRevokeMessage.class.getDeclaredField("originalMessageType");
                    originalMessageTypeField.setAccessible(true);
                    int originalMessageType = messageMap.hasKey("originalMessageType")
                        ? messageMap.getInt("originalMessageType")
                        : 0;
                    originalMessageTypeField.set(message, ZIMMessageType.getZIMMessageType(originalMessageType));
                    originalMessageTypeField.setAccessible(false);

                    Field revokeStatusField = ZIMRevokeMessage.class.getDeclaredField("revokeStatus");
                    revokeStatusField.setAccessible(true);
                    int revokeStatus = messageMap.hasKey("revokeStatus") ? messageMap.getInt("revokeStatus") : -1;
                    revokeStatusField.set(message, ZIMMessageRevokeStatus.getZIMMessageRevokeStatus(revokeStatus));
                    revokeStatusField.setAccessible(false);

                    Field revokeTimestampField = ZIMRevokeMessage.class.getDeclaredField("revokeTimestamp");
                    revokeTimestampField.setAccessible(true);
                    long revokeTimestamp = messageMap.hasKey("revokeTimestamp")
                        ? Double.valueOf(messageMap.getDouble("revokeTimestamp")).longValue()
                        : 0;
                    revokeTimestampField.set(message, revokeTimestamp);
                    revokeTimestampField.setAccessible(false);

                    Field operatedUserIDField = ZIMRevokeMessage.class.getDeclaredField("operatedUserID");
                    operatedUserIDField.setAccessible(true);
                    String operatedUserID = messageMap.hasKey("operatedUserID")
                        ? messageMap.getString("operatedUserID")
                        : "";
                    operatedUserIDField.set(message, operatedUserID);
                    operatedUserIDField.setAccessible(false);

                    Field revokeExtendedDataField = ZIMRevokeMessage.class.getDeclaredField("revokeExtendedData");
                    revokeExtendedDataField.setAccessible(true);
                    String revokeExtendedData = messageMap.hasKey("revokeExtendedData")
                        ? messageMap.getString("revokeExtendedData")
                        : "";
                    revokeExtendedDataField.set(message, revokeExtendedData);
                    revokeExtendedDataField.setAccessible(false);

                    Field originalTextMessageContentField = ZIMRevokeMessage.class.getDeclaredField(
                        "originalTextMessageContent"
                    );
                    originalTextMessageContentField.setAccessible(true);
                    String originalTextMessageContent = messageMap.hasKey("originalTextMessageContent")
                        ? messageMap.getString("originalTextMessageContent")
                        : "";
                    originalTextMessageContentField.set(message, originalTextMessageContent);
                    originalTextMessageContentField.setAccessible(false);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case TIPS:
                message = new ZIMTipsMessage();
                ((ZIMTipsMessage) message).event = ZIMTipsMessageEvent.getZIMTipsMessageEvent(
                    messageMap.hasKey("event") ? messageMap.getInt("event") : 0
                );
                ((ZIMTipsMessage) message).operatedUser = messageMap.hasKey("operatedUser")
                    ? oSuperZIMGroupMemberSimpleInfo(messageMap.getMap("operatedUser"))
                    : null;
                ArrayList<ZIMUserInfo> targetUserList = new ArrayList<>();
                if (messageMap.getArray("targetUserList") != null) {
                    for (Object infoObj : messageMap.getArray("targetUserList").toArrayList()) {
                        targetUserList.add(oSuperZIMGroupMemberSimpleInfo((HashMap<String, Object>) infoObj));
                    }
                }
                ((ZIMTipsMessage) message).targetUserList = targetUserList;
                ((ZIMTipsMessage) message).changeInfo = messageMap.hasKey("changeInfo")
                    ? oZIMTipsMessageChangeInfo(messageMap.getMap("changeInfo"))
                    : null;
                break;
            case CUSTOM:
                String customContent = messageMap.hasKey("message") ? messageMap.getString("message") : "";
                int subType = messageMap.hasKey("subType") ? messageMap.getInt("subType") : 0;
                message = new ZIMCustomMessage(customContent, subType);
                ((ZIMCustomMessage) message).searchedContent = messageMap.hasKey("searchedContent")
                    ? messageMap.getString("searchedContent")
                    : "";
                break;
            case COMBINE:
                String combineTitle = messageMap.hasKey("title") ? messageMap.getString("title") : "";
                String combineSummary = messageMap.hasKey("summary") ? messageMap.getString("summary") : "";
                message = new ZIMCombineMessage(
                    combineTitle,
                    combineSummary,
                    oZIMMessageList(messageMap.getArray("messageList"))
                );
                try {
                    if (messageMap.hasKey("combineID")) {
                        Field combineIDField = ZIMCombineMessage.class.getDeclaredField("combineID");
                        combineIDField.setAccessible(true);
                        combineIDField.set(message, messageMap.getString("combineID"));
                        combineIDField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case IMAGE:
                String imageFileLocalPath = messageMap.hasKey("fileLocalPath")
                    ? messageMap.getString("fileLocalPath")
                    : "";
                message = new ZIMImageMessage(imageFileLocalPath);
                if (messageMap.hasKey("thumbnailDownloadUrl")) {
                    ((ZIMImageMessage) message).setThumbnailDownloadUrl(messageMap.getString("thumbnailDownloadUrl"));
                }

                if (messageMap.hasKey("largeImageDownloadUrl")) {
                    ((ZIMImageMessage) message).setLargeImageDownloadUrl(messageMap.getString("largeImageDownloadUrl"));
                }

                try {
                    if (messageMap.hasKey("thumbnailLocalPath")) {
                        Field thumbnailLocalPathField = ZIMImageMessage.class.getDeclaredField("thumbnailLocalPath");
                        thumbnailLocalPathField.setAccessible(true);
                        thumbnailLocalPathField.set(message, messageMap.getString("thumbnailLocalPath"));
                        thumbnailLocalPathField.setAccessible(false);
                    }

                    if (messageMap.hasKey("largeImageLocalPath")) {
                        Field largeImageLocalPathField = ZIMImageMessage.class.getDeclaredField("largeImageLocalPath");
                        largeImageLocalPathField.setAccessible(true);
                        largeImageLocalPathField.set(message, messageMap.getString("largeImageLocalPath"));
                        largeImageLocalPathField.setAccessible(false);
                    }

                    if (messageMap.hasKey("originalImageWidth")) {
                        Field originalImageWidthField = ZIMImageMessage.class.getDeclaredField("originalImageWidth");
                        originalImageWidthField.setAccessible(true);
                        originalImageWidthField.set(message, messageMap.getInt("originalImageWidth"));
                        originalImageWidthField.setAccessible(false);
                    }

                    if (messageMap.hasKey("originalImageHeight")) {
                        Field originalImageHeightField = ZIMImageMessage.class.getDeclaredField("originalImageHeight");
                        originalImageHeightField.setAccessible(true);
                        originalImageHeightField.set(message, messageMap.getInt("originalImageHeight"));
                        originalImageHeightField.setAccessible(false);
                    }

                    if (messageMap.hasKey("thumbnailWidth")) {
                        Field thumbnailWidthField = ZIMImageMessage.class.getDeclaredField("thumbnailWidth");
                        thumbnailWidthField.setAccessible(true);
                        thumbnailWidthField.set(message, messageMap.getInt("thumbnailWidth"));
                        thumbnailWidthField.setAccessible(false);
                    }

                    if (messageMap.hasKey("thumbnailHeight")) {
                        Field thumbnailHeightField = ZIMImageMessage.class.getDeclaredField("thumbnailHeight");
                        thumbnailHeightField.setAccessible(true);
                        thumbnailHeightField.set(message, messageMap.getInt("thumbnailHeight"));
                        thumbnailHeightField.setAccessible(false);
                    }

                    if (messageMap.hasKey("largeImageWidth")) {
                        Field largeImageWidthField = ZIMImageMessage.class.getDeclaredField("largeImageWidth");
                        largeImageWidthField.setAccessible(true);
                        largeImageWidthField.set(message, messageMap.getInt("largeImageWidth"));
                        largeImageWidthField.setAccessible(false);
                    }

                    if (messageMap.hasKey("largeImageHeight")) {
                        Field largeImageHeightField = ZIMImageMessage.class.getDeclaredField("largeImageHeight");
                        largeImageHeightField.setAccessible(true);
                        largeImageHeightField.set(message, messageMap.getInt("largeImageHeight"));
                        largeImageHeightField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case FILE:
                String fileLocalPath = messageMap.hasKey("fileLocalPath") ? messageMap.getString("fileLocalPath") : "";
                message = new ZIMFileMessage(fileLocalPath);
                break;
            case VIDEO:
                String videoFileLocalPath = messageMap.hasKey("fileLocalPath")
                    ? messageMap.getString("fileLocalPath")
                    : "";
                long videoDuration = messageMap.hasKey("videoDuration")
                    ? Double.valueOf(messageMap.getDouble("videoDuration")).longValue()
                    : 0;
                message = new ZIMVideoMessage(videoFileLocalPath, videoDuration);
                try {
                    if (messageMap.hasKey("videoFirstFrameDownloadUrl")) {
                        ((ZIMVideoMessage) message).setVideoFirstFrameDownloadUrl(
                            messageMap.getString("videoFirstFrameDownloadUrl")
                        );
                    }

                    if (messageMap.hasKey("videoFirstFrameLocalPath")) {
                        Field videoFirstFrameLocalPathField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameLocalPath"
                        );
                        videoFirstFrameLocalPathField.setAccessible(true);
                        videoFirstFrameLocalPathField.set(message, messageMap.getString("videoFirstFrameLocalPath"));
                        videoFirstFrameLocalPathField.setAccessible(false);
                    }

                    if (messageMap.hasKey("videoFirstFrameWidth")) {
                        Field videoFirstFrameWidthField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameWidth"
                        );
                        videoFirstFrameWidthField.setAccessible(true);
                        videoFirstFrameWidthField.set(message, messageMap.getInt("videoFirstFrameWidth"));
                        videoFirstFrameWidthField.setAccessible(false);
                    }

                    if (messageMap.hasKey("videoFirstFrameHeight")) {
                        Field videoFirstFrameHeightField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameHeight"
                        );
                        videoFirstFrameHeightField.setAccessible(true);
                        videoFirstFrameHeightField.set(message, messageMap.getInt("videoFirstFrameHeight"));
                        videoFirstFrameHeightField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case AUDIO:
                String audioFileLocalPath = messageMap.hasKey("fileLocalPath")
                    ? messageMap.getString("fileLocalPath")
                    : "";
                long audioDuration = messageMap.hasKey("audioDuration")
                    ? Double.valueOf(messageMap.getDouble("audioDuration")).longValue()
                    : 0;
                message = new ZIMAudioMessage(audioFileLocalPath, audioDuration);
                break;
            case MULTIPLE:
                message = new ZIMMultipleMessage();
                if (messageMap.getArray("messageInfoList") != null) {
                    ArrayList<ZIMMessageLiteInfo> messageInfoList = new ArrayList<>();
                    for (Object messageObj : messageMap.getArray("messageInfoList").toArrayList()) {
                        messageInfoList.add(oZIMMessageLiteInfo((HashMap<String, Object>) messageObj));
                    }
                    ((ZIMMultipleMessage) message).setMessageInfoList(messageInfoList);
                }
                if (messageMap.getArray("failedIndexList") != null) {
                    ((ZIMMultipleMessage) message).setFailedIndexList(
                        oIntArray(messageMap.getArray("failedIndexList"))
                    );
                }
                break;
            default:
                message = new ZIMMessage(ZIMMessageType.UNKNOWN);
                break;
        }

        try {
            // public field

            message.extendedData = messageMap.hasKey("extendedData") ? messageMap.getString("extendedData") : "";
            message.localExtendedData = messageMap.hasKey("localExtendedData")
                ? messageMap.getString("localExtendedData")
                : "";

            // private field

            Field msgTypeField = ZIMMessage.class.getDeclaredField("type");
            msgTypeField.setAccessible(true);
            msgTypeField.set(message, ZIMMessageType.getZIMMessageType(messageMap.getInt("type")));
            msgTypeField.setAccessible(false);

            Field messageIDField = ZIMMessage.class.getDeclaredField("messageID");
            messageIDField.setAccessible(true);
            long messageID = messageMap.hasKey("messageID")
                ? Long.valueOf(messageMap.getString("messageID")).longValue()
                : 0;
            messageIDField.set(message, messageID);
            messageIDField.setAccessible(false);

            Field conversationIDField = ZIMMessage.class.getDeclaredField("conversationID");
            conversationIDField.setAccessible(true);
            String conversationID = messageMap.hasKey("conversationID") ? messageMap.getString("conversationID") : "";
            conversationIDField.set(message, conversationID);
            conversationIDField.setAccessible(false);

            Field messageSeqField = ZIMMessage.class.getDeclaredField("messageSeq");
            messageSeqField.setAccessible(true);
            long messageSeq = messageMap.hasKey("messageSeq")
                ? Double.valueOf(messageMap.getDouble("messageSeq")).longValue()
                : 0;
            messageSeqField.set(message, messageSeq);
            messageSeqField.setAccessible(false);

            Field senderUserIDField = ZIMMessage.class.getDeclaredField("senderUserID");
            senderUserIDField.setAccessible(true);
            String senderUserID = messageMap.hasKey("senderUserID") ? messageMap.getString("senderUserID") : "";
            senderUserIDField.set(message, senderUserID);
            senderUserIDField.setAccessible(false);

            Field timestampField = ZIMMessage.class.getDeclaredField("timestamp");
            timestampField.setAccessible(true);
            long timestamp = messageMap.hasKey("timestamp")
                ? Double.valueOf(messageMap.getDouble("timestamp")).longValue()
                : 0;
            timestampField.set(message, timestamp);
            timestampField.setAccessible(false);

            Field localMessageIDField = ZIMMessage.class.getDeclaredField("localMessageID");
            localMessageIDField.setAccessible(true);
            long localMessageID = messageMap.hasKey("localMessageID")
                ? Long.valueOf(messageMap.getString("localMessageID")).longValue()
                : 0;
            localMessageIDField.set(message, localMessageID);
            localMessageIDField.setAccessible(false);

            Field conversationTypeField = ZIMMessage.class.getDeclaredField("conversationType");
            conversationTypeField.setAccessible(true);
            int conversationType = messageMap.hasKey("conversationType") ? messageMap.getInt("conversationType") : -1;
            conversationTypeField.set(message, ZIMConversationType.getZIMConversationType(conversationType));
            conversationTypeField.setAccessible(false);

            Field directionField = ZIMMessage.class.getDeclaredField("direction");
            directionField.setAccessible(true);
            int direction = messageMap.hasKey("direction") ? messageMap.getInt("direction") : -1;
            directionField.set(message, ZIMMessageDirection.getZIMMessageDirection(direction));
            directionField.setAccessible(false);

            Field sentStatusField = ZIMMessage.class.getDeclaredField("sentStatus");
            sentStatusField.setAccessible(true);
            int sentStatus = messageMap.hasKey("sentStatus") ? messageMap.getInt("sentStatus") : -1;
            sentStatusField.set(message, ZIMMessageSentStatus.getZIMMessageSentStatus(sentStatus));
            sentStatusField.setAccessible(false);

            Field orderKeyField = ZIMMessage.class.getDeclaredField("orderKey");
            orderKeyField.setAccessible(true);
            long orderKey = messageMap.hasKey("orderKey")
                ? Double.valueOf(messageMap.getDouble("orderKey")).longValue()
                : 0;
            orderKeyField.set(message, orderKey);
            orderKeyField.setAccessible(false);

            Field receiptStatusField = ZIMMessage.class.getDeclaredField("receiptStatus");
            receiptStatusField.setAccessible(true);
            int receiptStatus = messageMap.hasKey("receiptStatus") ? messageMap.getInt("receiptStatus") : 0;
            receiptStatusField.set(message, ZIMMessageReceiptStatus.getZIMMessageReceiptStatus(receiptStatus));
            receiptStatusField.setAccessible(false);

            Field isUserInsertedField = ZIMMessage.class.getDeclaredField("isUserInserted");
            isUserInsertedField.setAccessible(true);
            boolean isUserInserted = messageMap.hasKey("isUserInserted")
                ? messageMap.getBoolean("isUserInserted")
                : false;
            isUserInsertedField.set(message, isUserInserted);
            isUserInsertedField.setAccessible(false);

            Field isBroadcastMessageField = ZIMMessage.class.getDeclaredField("isBroadcastMessage");
            isBroadcastMessageField.setAccessible(true);
            boolean isBroadcastMessage = messageMap.hasKey("isBroadcastMessage")
                ? messageMap.getBoolean("isBroadcastMessage")
                : false;
            isBroadcastMessageField.set(message, isBroadcastMessage);
            isBroadcastMessageField.setAccessible(false);

            Field isServerMessageField = ZIMMessage.class.getDeclaredField("isServerMessage");
            isServerMessageField.setAccessible(true);
            boolean isServerMessage = messageMap.hasKey("isServerMessage")
                ? messageMap.getBoolean("isServerMessage")
                : false;
            isServerMessageField.set(message, isServerMessage);
            isServerMessageField.setAccessible(false);

            Field isGroupTargetedMessageField = ZIMMessage.class.getDeclaredField("isGroupTargetedMessage");
            isGroupTargetedMessageField.setAccessible(true);
            boolean isGroupTargetedMessage = messageMap.hasKey("isGroupTargetedMessage")
                ? messageMap.getBoolean("isGroupTargetedMessage")
                : false;
            isGroupTargetedMessageField.set(message, isGroupTargetedMessage);
            isGroupTargetedMessageField.setAccessible(false);

            Field isMentionAllField = ZIMMessage.class.getDeclaredField("isMentionAll");
            isMentionAllField.setAccessible(true);
            boolean isMentionAll = messageMap.hasKey("isMentionAll") ? messageMap.getBoolean("isMentionAll") : false;
            isMentionAllField.set(message, isMentionAll);
            isMentionAllField.setAccessible(false);

            if (messageMap.getArray("mentionedUserIDs") != null) {
                Field mentionedUserIDsField = ZIMMessage.class.getDeclaredField("mentionedUserIDs");
                mentionedUserIDsField.setAccessible(true);
                mentionedUserIDsField.set(message, oStringArray(messageMap.getArray("mentionedUserIDs")));
                mentionedUserIDsField.setAccessible(false);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        if (message instanceof ZIMMediaMessage) {
            try {
                if (messageMap.hasKey("fileDownloadUrl")) {
                    ((ZIMMediaMessage) message).setFileDownloadUrl(messageMap.getString("fileDownloadUrl"));
                }
                if (messageMap.hasKey("fileUID")) {
                    Field fileUIDField = ZIMMediaMessage.class.getDeclaredField("fileUID");
                    fileUIDField.setAccessible(true);
                    fileUIDField.set(message, messageMap.getString("fileUID"));
                    fileUIDField.setAccessible(false);
                }

                if (messageMap.hasKey("fileName")) {
                    Field fileNameField = ZIMMediaMessage.class.getDeclaredField("fileName");
                    fileNameField.setAccessible(true);
                    fileNameField.set(message, messageMap.getString("fileName"));
                    fileNameField.setAccessible(false);
                }

                if (messageMap.hasKey("fileSize")) {
                    Field fileSizeField = ZIMMediaMessage.class.getDeclaredField("fileSize");
                    fileSizeField.setAccessible(true);
                    fileSizeField.set(message, Double.valueOf(messageMap.getDouble("fileSize")).longValue());
                    fileSizeField.setAccessible(false);
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return message;
    }

    // Used for queried messages
    public static ZIMMessage oZIMMessage(HashMap<String, Object> messageMap) {
        if (messageMap == null) {
            return null;
        }

        ZIMMessage message = null;
        ZIMMessageType type = ZIMMessageType.getZIMMessageType(
            Double.valueOf((double) messageMap.get("type")).intValue()
        );
        switch (type) {
            case TEXT:
                message = new ZIMTextMessage((String) messageMap.get("message"));
                break;
            case COMMAND:
                ArrayList byteArr = (ArrayList) messageMap.get("message");
                int size = byteArr.size();
                byte[] bytes = new byte[size];
                for (int i = 0; i < size; i++) {
                    int b = Double.valueOf((double) byteArr.get(i)).intValue();
                    bytes[i] = (byte) (b < 128 ? b : b - 256);
                }
                message = new ZIMCommandMessage(bytes);
                break;
            case BARRAGE:
                message = new ZIMBarrageMessage((String) messageMap.get("message"));
                break;
            case REVOKE:
                message = new ZIMRevokeMessage();
                try {
                    Field revokeTypeField = ZIMRevokeMessage.class.getDeclaredField("revokeType");
                    revokeTypeField.setAccessible(true);
                    int revokeType = messageMap.containsKey("revokeType")
                        ? Double.valueOf((double) messageMap.get("revokeType")).intValue()
                        : -1;
                    revokeTypeField.set(message, ZIMRevokeType.getZIMRevokeType(revokeType));
                    revokeTypeField.setAccessible(false);

                    Field originalMessageTypeField = ZIMRevokeMessage.class.getDeclaredField("originalMessageType");
                    originalMessageTypeField.setAccessible(true);
                    int originalMessageType = messageMap.containsKey("originalMessageType")
                        ? Double.valueOf((double) messageMap.get("originalMessageType")).intValue()
                        : 0;
                    originalMessageTypeField.set(message, ZIMMessageType.getZIMMessageType(originalMessageType));
                    originalMessageTypeField.setAccessible(false);

                    Field revokeStatusField = ZIMRevokeMessage.class.getDeclaredField("revokeStatus");
                    revokeStatusField.setAccessible(true);
                    int revokeStatus = messageMap.containsKey("revokeStatus")
                        ? Double.valueOf((double) messageMap.get("revokeStatus")).intValue()
                        : -1;
                    revokeStatusField.set(message, ZIMMessageRevokeStatus.getZIMMessageRevokeStatus(revokeStatus));
                    revokeStatusField.setAccessible(false);

                    Field revokeTimestampField = ZIMRevokeMessage.class.getDeclaredField("revokeTimestamp");
                    revokeTimestampField.setAccessible(true);
                    long revokeTimestamp = messageMap.containsKey("revokeTimestamp")
                        ? Double.valueOf((double) messageMap.get("revokeTimestamp")).longValue()
                        : 0;
                    revokeTimestampField.set(message, revokeTimestamp);
                    revokeTimestampField.setAccessible(false);

                    Field operatedUserIDField = ZIMRevokeMessage.class.getDeclaredField("operatedUserID");
                    operatedUserIDField.setAccessible(true);
                    String operatedUserID = messageMap.containsKey("operatedUserID")
                        ? (String) messageMap.get("operatedUserID")
                        : "";
                    operatedUserIDField.set(message, operatedUserID);
                    operatedUserIDField.setAccessible(false);

                    Field revokeExtendedDataField = ZIMRevokeMessage.class.getDeclaredField("revokeExtendedData");
                    revokeExtendedDataField.setAccessible(true);
                    String revokeExtendedData = messageMap.containsKey("revokeExtendedData")
                        ? (String) messageMap.get("revokeExtendedData")
                        : "";
                    revokeExtendedDataField.set(message, revokeExtendedData);
                    revokeExtendedDataField.setAccessible(false);

                    Field originalTextMessageContentField = ZIMRevokeMessage.class.getDeclaredField(
                        "originalTextMessageContent"
                    );
                    originalTextMessageContentField.setAccessible(true);
                    String originalTextMessageContent = messageMap.containsKey("originalTextMessageContent")
                        ? (String) messageMap.get("originalTextMessageContent")
                        : "";
                    originalTextMessageContentField.set(message, originalTextMessageContent);
                    originalTextMessageContentField.setAccessible(false);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case TIPS:
                message = new ZIMTipsMessage();
                ((ZIMTipsMessage) message).event = ZIMTipsMessageEvent.getZIMTipsMessageEvent(
                    messageMap.containsKey("event") ? Double.valueOf((double) messageMap.get("event")).intValue() : 0
                );
                ((ZIMTipsMessage) message).operatedUser = messageMap.containsKey("operatedUser")
                    ? oSuperZIMGroupMemberSimpleInfo((HashMap<String, Object>) messageMap.get("operatedUser"))
                    : null;
                ArrayList<ZIMUserInfo> targetUserList = new ArrayList<>();
                if (messageMap.get("targetUserList") != null) {
                    for (Object infoObj : (ArrayList) messageMap.get("targetUserList")) {
                        targetUserList.add(oSuperZIMGroupMemberSimpleInfo((HashMap<String, Object>) infoObj));
                    }
                }
                ((ZIMTipsMessage) message).targetUserList = targetUserList;
                ((ZIMTipsMessage) message).changeInfo = messageMap.containsKey("changeInfo")
                    ? oZIMTipsMessageChangeInfo((HashMap<String, Object>) messageMap.get("changeInfo"))
                    : null;
                break;
            case CUSTOM:
                int subType = messageMap.containsKey("subType")
                    ? Double.valueOf((double) messageMap.get("subType")).intValue()
                    : 0;
                message = new ZIMCustomMessage((String) messageMap.get("message"), subType);
                if (messageMap.containsKey("searchedContent")) {
                    ((ZIMCustomMessage) message).searchedContent = (String) messageMap.get("searchedContent");
                }
                break;
            case COMBINE:
                String combineTitle = messageMap.containsKey("title") ? (String) messageMap.get("title") : "";
                String combineSummary = messageMap.containsKey("summary") ? (String) messageMap.get("summary") : "";
                ArrayList<ZIMMessage> combineMessageList = new ArrayList<>();
                if (messageMap.get("messageList") != null) {
                    for (Object messageObj : (ArrayList) messageMap.get("messageList")) {
                        combineMessageList.add(oZIMMessage((HashMap<String, Object>) messageObj));
                    }
                }

                message = new ZIMCombineMessage(combineTitle, combineSummary, combineMessageList);
                try {
                    if (messageMap.containsKey("combineID")) {
                        Field combineIDField = ZIMCombineMessage.class.getDeclaredField("combineID");
                        combineIDField.setAccessible(true);
                        combineIDField.set(message, (String) messageMap.get("combineID"));
                        combineIDField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case IMAGE:
                message = new ZIMImageMessage((String) messageMap.get("fileLocalPath"));
                if (messageMap.containsKey("thumbnailDownloadUrl")) {
                    ((ZIMImageMessage) message).setThumbnailDownloadUrl(
                        (String) messageMap.get("thumbnailDownloadUrl")
                    );
                }

                if (messageMap.containsKey("largeImageDownloadUrl")) {
                    ((ZIMImageMessage) message).setLargeImageDownloadUrl(
                        (String) messageMap.get("largeImageDownloadUrl")
                    );
                }

                try {
                    if (messageMap.containsKey("thumbnailLocalPath")) {
                        Field thumbnailLocalPathField = ZIMImageMessage.class.getDeclaredField("thumbnailLocalPath");
                        thumbnailLocalPathField.setAccessible(true);
                        thumbnailLocalPathField.set(message, (String) messageMap.get("thumbnailLocalPath"));
                        thumbnailLocalPathField.setAccessible(false);
                    }

                    if (messageMap.containsKey("largeImageLocalPath")) {
                        Field largeImageLocalPathField = ZIMImageMessage.class.getDeclaredField("largeImageLocalPath");
                        largeImageLocalPathField.setAccessible(true);
                        largeImageLocalPathField.set(message, (String) messageMap.get("largeImageLocalPath"));
                        largeImageLocalPathField.setAccessible(false);
                    }

                    if (messageMap.containsKey("originalImageWidth")) {
                        Field originalImageWidthField = ZIMImageMessage.class.getDeclaredField("originalImageWidth");
                        originalImageWidthField.setAccessible(true);
                        originalImageWidthField.set(
                            message,
                            Double.valueOf((double) messageMap.get("originalImageWidth")).intValue()
                        );
                        originalImageWidthField.setAccessible(false);
                    }

                    if (messageMap.containsKey("originalImageHeight")) {
                        Field originalImageHeightField = ZIMImageMessage.class.getDeclaredField("originalImageHeight");
                        originalImageHeightField.setAccessible(true);
                        originalImageHeightField.set(
                            message,
                            Double.valueOf((double) messageMap.get("originalImageHeight")).intValue()
                        );
                        originalImageHeightField.setAccessible(false);
                    }

                    if (messageMap.containsKey("thumbnailWidth")) {
                        Field thumbnailWidthField = ZIMImageMessage.class.getDeclaredField("thumbnailWidth");
                        thumbnailWidthField.setAccessible(true);
                        thumbnailWidthField.set(
                            message,
                            Double.valueOf((double) messageMap.get("thumbnailWidth")).intValue()
                        );
                        thumbnailWidthField.setAccessible(false);
                    }

                    if (messageMap.containsKey("thumbnailHeight")) {
                        Field thumbnailHeightField = ZIMImageMessage.class.getDeclaredField("thumbnailHeight");
                        thumbnailHeightField.setAccessible(true);
                        thumbnailHeightField.set(
                            message,
                            Double.valueOf((double) messageMap.get("thumbnailHeight")).intValue()
                        );
                        thumbnailHeightField.setAccessible(false);
                    }

                    if (messageMap.containsKey("largeImageWidth")) {
                        Field largeImageWidthField = ZIMImageMessage.class.getDeclaredField("largeImageWidth");
                        largeImageWidthField.setAccessible(true);
                        largeImageWidthField.set(
                            message,
                            Double.valueOf((double) messageMap.get("largeImageWidth")).intValue()
                        );
                        largeImageWidthField.setAccessible(false);
                    }

                    if (messageMap.containsKey("largeImageHeight")) {
                        Field largeImageHeightField = ZIMImageMessage.class.getDeclaredField("largeImageHeight");
                        largeImageHeightField.setAccessible(true);
                        largeImageHeightField.set(
                            message,
                            Double.valueOf((double) messageMap.get("largeImageHeight")).intValue()
                        );
                        largeImageHeightField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case FILE:
                message = new ZIMFileMessage((String) messageMap.get("fileLocalPath"));
                break;
            case VIDEO:
                message = new ZIMVideoMessage(
                    (String) messageMap.get("fileLocalPath"),
                    Double.valueOf((double) messageMap.get("videoDuration")).longValue()
                );
                try {
                    if (messageMap.containsKey("videoFirstFrameDownloadUrl")) {
                        ((ZIMVideoMessage) message).setVideoFirstFrameDownloadUrl(
                            (String) messageMap.get("videoFirstFrameDownloadUrl")
                        );
                    }

                    if (messageMap.containsKey("videoFirstFrameLocalPath")) {
                        Field videoFirstFrameLocalPathField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameLocalPath"
                        );
                        videoFirstFrameLocalPathField.setAccessible(true);
                        videoFirstFrameLocalPathField.set(message, (String) messageMap.get("videoFirstFrameLocalPath"));
                        videoFirstFrameLocalPathField.setAccessible(false);
                    }

                    if (messageMap.containsKey("videoFirstFrameWidth")) {
                        Field videoFirstFrameWidthField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameWidth"
                        );
                        videoFirstFrameWidthField.setAccessible(true);
                        videoFirstFrameWidthField.set(
                            message,
                            Double.valueOf((double) messageMap.get("videoFirstFrameWidth")).intValue()
                        );
                        videoFirstFrameWidthField.setAccessible(false);
                    }

                    if (messageMap.containsKey("videoFirstFrameHeight")) {
                        Field videoFirstFrameHeightField = ZIMVideoMessage.class.getDeclaredField(
                            "videoFirstFrameHeight"
                        );
                        videoFirstFrameHeightField.setAccessible(true);
                        videoFirstFrameHeightField.set(
                            message,
                            Double.valueOf((double) messageMap.get("videoFirstFrameHeight")).intValue()
                        );
                        videoFirstFrameHeightField.setAccessible(false);
                    }
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                break;
            case AUDIO:
                message = new ZIMAudioMessage(
                    (String) messageMap.get("fileLocalPath"),
                    Double.valueOf((double) messageMap.get("audioDuration")).longValue()
                );
                break;
            case MULTIPLE:
                message = new ZIMMultipleMessage();
                if (messageMap.get("messageInfoList") != null) {
                    ArrayList<ZIMMessageLiteInfo> messageInfoList = new ArrayList<>();
                    for (Object messageObj : (ArrayList) messageMap.get("messageInfoList")) {
                        messageInfoList.add(oZIMMessageLiteInfo((HashMap<String, Object>) messageObj));
                    }
                    ((ZIMMultipleMessage) message).setMessageInfoList(messageInfoList);
                }
                if (messageMap.get("failedIndexList") != null) {
                    ArrayList<Integer> failedIndexList = new ArrayList<>();
                    for (Object key : (ArrayList) messageMap.get("failedIndexList")) {
                        failedIndexList.add(Double.valueOf((double) key).intValue());
                    }
                    ((ZIMMultipleMessage) message).setFailedIndexList(failedIndexList);
                }
                break;
            default:
                message = new ZIMMessage(ZIMMessageType.UNKNOWN);
                break;
        }

        try {
            // public field

            message.extendedData = messageMap.containsKey("extendedData")
                ? (String) messageMap.get("extendedData")
                : "";
            message.localExtendedData = messageMap.containsKey("localExtendedData")
                ? (String) messageMap.get("localExtendedData")
                : "";

            // private field

            Field msgTypeField = ZIMMessage.class.getDeclaredField("type");
            msgTypeField.setAccessible(true);
            msgTypeField.set(message, type);
            msgTypeField.setAccessible(false);

            Field messageIDField = ZIMMessage.class.getDeclaredField("messageID");
            messageIDField.setAccessible(true);
            long messageID = messageMap.containsKey("messageID")
                ? Long.valueOf((String) messageMap.get("messageID")).longValue()
                : 0;
            messageIDField.set(message, messageID);
            messageIDField.setAccessible(false);

            Field conversationIDField = ZIMMessage.class.getDeclaredField("conversationID");
            conversationIDField.setAccessible(true);
            String conversationID = messageMap.containsKey("conversationID")
                ? (String) messageMap.get("conversationID")
                : "";
            conversationIDField.set(message, conversationID);
            conversationIDField.setAccessible(false);

            Field messageSeqField = ZIMMessage.class.getDeclaredField("messageSeq");
            messageSeqField.setAccessible(true);
            long messageSeq = messageMap.containsKey("messageSeq")
                ? Double.valueOf((double) messageMap.get("messageSeq")).longValue()
                : 0;
            messageSeqField.set(message, messageSeq);
            messageSeqField.setAccessible(false);

            Field senderUserIDField = ZIMMessage.class.getDeclaredField("senderUserID");
            senderUserIDField.setAccessible(true);
            String senderUserID = messageMap.containsKey("senderUserID") ? (String) messageMap.get("senderUserID") : "";
            senderUserIDField.set(message, senderUserID);
            senderUserIDField.setAccessible(false);

            Field timestampField = ZIMMessage.class.getDeclaredField("timestamp");
            timestampField.setAccessible(true);
            long timestamp = messageMap.containsKey("timestamp")
                ? Double.valueOf((double) messageMap.get("timestamp")).longValue()
                : 0;
            timestampField.set(message, timestamp);
            timestampField.setAccessible(false);

            Field localMessageIDField = ZIMMessage.class.getDeclaredField("localMessageID");
            localMessageIDField.setAccessible(true);
            long localMessageID = messageMap.containsKey("localMessageID")
                ? Long.valueOf((String) messageMap.get("localMessageID")).longValue()
                : 0;
            localMessageIDField.set(message, localMessageID);
            localMessageIDField.setAccessible(false);

            Field conversationTypeField = ZIMMessage.class.getDeclaredField("conversationType");
            conversationTypeField.setAccessible(true);
            int conversationType = messageMap.containsKey("conversationType")
                ? Double.valueOf((double) messageMap.get("conversationType")).intValue()
                : -1;
            conversationTypeField.set(message, ZIMConversationType.getZIMConversationType(conversationType));
            conversationTypeField.setAccessible(false);

            Field directionField = ZIMMessage.class.getDeclaredField("direction");
            directionField.setAccessible(true);
            int direction = messageMap.containsKey("direction")
                ? Double.valueOf((double) messageMap.get("direction")).intValue()
                : -1;
            directionField.set(message, ZIMMessageDirection.getZIMMessageDirection(direction));
            directionField.setAccessible(false);

            Field sentStatusField = ZIMMessage.class.getDeclaredField("sentStatus");
            sentStatusField.setAccessible(true);
            int sentStatus = messageMap.containsKey("sentStatus")
                ? Double.valueOf((double) messageMap.get("sentStatus")).intValue()
                : -1;
            sentStatusField.set(message, ZIMMessageSentStatus.getZIMMessageSentStatus(sentStatus));
            sentStatusField.setAccessible(false);

            Field orderKeyField = ZIMMessage.class.getDeclaredField("orderKey");
            orderKeyField.setAccessible(true);
            long orderKey = messageMap.containsKey("orderKey")
                ? Double.valueOf((double) messageMap.get("orderKey")).longValue()
                : 0;
            orderKeyField.set(message, orderKey);
            orderKeyField.setAccessible(false);

            Field receiptStatusField = ZIMMessage.class.getDeclaredField("receiptStatus");
            receiptStatusField.setAccessible(true);
            int receiptStatus = messageMap.containsKey("receiptStatus")
                ? Double.valueOf((double) messageMap.get("receiptStatus")).intValue()
                : 0;
            receiptStatusField.set(message, ZIMMessageReceiptStatus.getZIMMessageReceiptStatus(receiptStatus));
            receiptStatusField.setAccessible(false);

            Field isUserInsertedField = ZIMMessage.class.getDeclaredField("isUserInserted");
            isUserInsertedField.setAccessible(true);
            boolean isUserInserted = messageMap.containsKey("isUserInserted")
                ? ((Boolean) messageMap.get("isUserInserted")).booleanValue()
                : false;
            isUserInsertedField.set(message, isUserInserted);
            isUserInsertedField.setAccessible(false);

            Field isBroadcastMessageField = ZIMMessage.class.getDeclaredField("isBroadcastMessage");
            isBroadcastMessageField.setAccessible(true);
            boolean isBroadcastMessage = messageMap.containsKey("isBroadcastMessage")
                ? ((Boolean) messageMap.get("isBroadcastMessage")).booleanValue()
                : false;
            isBroadcastMessageField.set(message, isBroadcastMessage);
            isBroadcastMessageField.setAccessible(false);

            Field isServerMessageField = ZIMMessage.class.getDeclaredField("isServerMessage");
            isServerMessageField.setAccessible(true);
            boolean isServerMessage = messageMap.containsKey("isServerMessage")
                ? ((Boolean) messageMap.get("isServerMessage")).booleanValue()
                : false;
            isServerMessageField.set(message, isServerMessage);
            isServerMessageField.setAccessible(false);

            Field isGroupTargetedMessageField = ZIMMessage.class.getDeclaredField("isGroupTargetedMessage");
            isGroupTargetedMessageField.setAccessible(true);
            boolean isGroupTargetedMessage = messageMap.containsKey("isGroupTargetedMessage")
                ? ((Boolean) messageMap.get("isGroupTargetedMessage")).booleanValue()
                : false;
            isGroupTargetedMessageField.set(message, isGroupTargetedMessage);
            isGroupTargetedMessageField.setAccessible(false);

            Field isMentionAllField = ZIMMessage.class.getDeclaredField("isMentionAll");
            isMentionAllField.setAccessible(true);
            boolean isMentionAll = messageMap.containsKey("isMentionAll")
                ? ((Boolean) messageMap.get("isMentionAll")).booleanValue()
                : false;
            isMentionAllField.set(message, isMentionAll);
            isMentionAllField.setAccessible(false);

            if (messageMap.get("mentionedUserIDs") != null) {
                Field mentionedUserIDsField = ZIMMessage.class.getDeclaredField("mentionedUserIDs");
                mentionedUserIDsField.setAccessible(true);
                mentionedUserIDsField.set(message, (ArrayList<String>) messageMap.get("mentionedUserIDs"));
                mentionedUserIDsField.setAccessible(false);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        if (message instanceof ZIMMediaMessage) {
            if (messageMap.containsKey("fileDownloadUrl")) {
                ((ZIMMediaMessage) message).setFileDownloadUrl((String) messageMap.get("fileDownloadUrl"));
            }
            try {
                if (messageMap.containsKey("fileUID")) {
                    Field fileUIDField = ZIMMediaMessage.class.getDeclaredField("fileUID");
                    fileUIDField.setAccessible(true);
                    fileUIDField.set(message, (String) messageMap.get("fileUID"));
                    fileUIDField.setAccessible(false);
                }

                if (messageMap.containsKey("fileName")) {
                    Field fileNameField = ZIMMediaMessage.class.getDeclaredField("fileName");
                    fileNameField.setAccessible(true);
                    fileNameField.set(message, (String) messageMap.get("fileName"));
                    fileNameField.setAccessible(false);
                }

                if (messageMap.containsKey("fileSize")) {
                    Field fileSizeField = ZIMMediaMessage.class.getDeclaredField("fileSize");
                    fileSizeField.setAccessible(true);
                    fileSizeField.set(message, Double.valueOf((double) messageMap.get("fileSize")).longValue());
                    fileSizeField.setAccessible(false);
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return message;
    }

    public static WritableMap mZIMMessage(ZIMMessage message) {
        WritableMap messageMap = Arguments.createMap();
        messageMap.putInt("type", message.getType().value());
        messageMap.putString("messageID", String.valueOf(message.getMessageID()));
        messageMap.putString("conversationID", message.getConversationID());
        messageMap.putDouble("messageSeq", message.getMessageSeq());
        messageMap.putString("senderUserID", message.getSenderUserID());
        messageMap.putDouble("timestamp", message.getTimestamp());
        messageMap.putString("localMessageID", String.valueOf(message.getLocalMessageID()));
        messageMap.putInt("conversationType", message.getConversationType().value());
        messageMap.putInt("direction", message.getDirection().value());
        messageMap.putInt("sentStatus", message.getSentStatus().value());
        messageMap.putDouble("orderKey", message.getOrderKey());
        messageMap.putBoolean("isUserInserted", message.getIsUserInserted());
        messageMap.putInt("receiptStatus", message.getReceiptStatus().value());
        messageMap.putString("extendedData", message.extendedData);
        messageMap.putString("localExtendedData", message.localExtendedData);
        messageMap.putBoolean("isBroadcastMessage", message.getIsBroadcastMessage());
        messageMap.putBoolean("isServerMessage", message.getIsServerMessage());
        messageMap.putBoolean("isGroupTargetedMessage", message.getIsGroupTargetedMessage());
        messageMap.putBoolean("isMentionAll", message.getIsMentionAll());
        messageMap.putInt("rootRepliedCount", message.getRootRepliedCount());
        messageMap.putMap("repliedInfo", mZIMMessageRepliedInfo(message.getRepliedInfo()));
        messageMap.putString("editorUserID", message.getEditorUserID());
        messageMap.putDouble("editedTime", message.getEditedTime());
        messageMap.putString("pinnedUserID", message.getPinnedUserID());
        messageMap.putDouble("pinnedTime", message.getPinnedTime());
        messageMap.putDouble("destructTime", message.getDestructTime());

        messageMap.putArray("reactions", mZIMMessageReactionList(message.getReactions()));
        messageMap.putArray("mentionedUserIDs", mStringArray(message.getMentionedUserIDs()));

        switch (message.getType()) {
            case TEXT:
                assert message instanceof ZIMTextMessage;
                messageMap.putString("message", ((ZIMTextMessage) message).message);
                break;
            case COMMAND:
                byte[] data = ((ZIMCommandMessage) message).message;
                WritableMap dataMap = Arguments.createMap();
                for (int i = 0; i < data.length; i++) {
                    int b = data[i];
                    dataMap.putInt(String.valueOf(i), b < 0 ? 256 + b : b);
                }
                messageMap.putMap("message", dataMap);
                break;
            case BARRAGE:
                assert message instanceof ZIMBarrageMessage;
                messageMap.putString("message", ((ZIMBarrageMessage) message).message);
                break;
            case REVOKE:
                assert message instanceof ZIMRevokeMessage;
                messageMap.putInt("revokeType", ((ZIMRevokeMessage) message).getRevokeType().value());
                messageMap.putInt("revokeStatus", ((ZIMRevokeMessage) message).getRevokeStatus().value());
                messageMap.putDouble("revokeTimestamp", ((ZIMRevokeMessage) message).getRevokeTimestamp());
                messageMap.putString("operatedUserID", ((ZIMRevokeMessage) message).getOperatedUserID());
                messageMap.putString("revokeExtendedData", ((ZIMRevokeMessage) message).getRevokeExtendedData());
                messageMap.putInt("originalMessageType", ((ZIMRevokeMessage) message).getOriginalMessageType().value());
                messageMap.putString(
                    "originalTextMessageContent",
                    ((ZIMRevokeMessage) message).getOriginalTextMessageContent()
                );
                break;
            case TIPS:
                assert message instanceof ZIMTipsMessage;
                messageMap.putInt("event", ((ZIMTipsMessage) message).event.value());
                messageMap.putMap(
                    "operatedUser",
                    mSuperZIMGroupMemberSimpleInfo(((ZIMTipsMessage) message).operatedUser)
                );
                messageMap.putArray(
                    "targetUserList",
                    mSuperZIMGroupMemberSimpleInfoList(((ZIMTipsMessage) message).targetUserList)
                );
                messageMap.putMap("changeInfo", mZIMTipsMessageChangeInfo(((ZIMTipsMessage) message).changeInfo));
                break;
            case CUSTOM:
                assert message instanceof ZIMCustomMessage;
                messageMap.putString("message", ((ZIMCustomMessage) message).message);
                messageMap.putInt("subType", ((ZIMCustomMessage) message).subType);
                messageMap.putString("searchedContent", ((ZIMCustomMessage) message).searchedContent);
                break;
            case COMBINE:
                assert message instanceof ZIMCombineMessage;
                messageMap.putString("title", ((ZIMCombineMessage) message).title);
                messageMap.putString("summary", ((ZIMCombineMessage) message).summary);
                messageMap.putString("combineID", ((ZIMCombineMessage) message).getCombineID());
                messageMap.putArray("messageList", mZIMMessageList(((ZIMCombineMessage) message).messageList));
                break;
            case IMAGE:
                assert message instanceof ZIMImageMessage;

                messageMap.putString(
                    "thumbnailDownloadUrl",
                    ((ZIMImageMessage) message).getThumbnailDownloadUrl() != null
                        ? ((ZIMImageMessage) message).getThumbnailDownloadUrl()
                        : ""
                );
                messageMap.putString(
                    "thumbnailLocalPath",
                    ((ZIMImageMessage) message).getThumbnailLocalPath() != null
                        ? ((ZIMImageMessage) message).getThumbnailLocalPath()
                        : ""
                );
                messageMap.putString(
                    "largeImageDownloadUrl",
                    ((ZIMImageMessage) message).getLargeImageDownloadUrl() != null
                        ? ((ZIMImageMessage) message).getLargeImageDownloadUrl()
                        : ""
                );
                messageMap.putString(
                    "largeImageLocalPath",
                    ((ZIMImageMessage) message).getLargeImageLocalPath() != null
                        ? ((ZIMImageMessage) message).getLargeImageLocalPath()
                        : ""
                );
                messageMap.putInt("originalImageWidth", ((ZIMImageMessage) message).getOriginalImageWidth());
                messageMap.putInt("originalImageHeight", ((ZIMImageMessage) message).getOriginalImageHeight());
                messageMap.putInt("thumbnailWidth", ((ZIMImageMessage) message).getThumbnailWidth());
                messageMap.putInt("thumbnailHeight", ((ZIMImageMessage) message).getThumbnailHeight());
                messageMap.putInt("largeImageWidth", ((ZIMImageMessage) message).getLargeImageWidth());
                messageMap.putInt("largeImageHeight", ((ZIMImageMessage) message).getLargeImageHeight());
                break;
            case VIDEO:
                assert message instanceof ZIMVideoMessage;

                messageMap.putDouble("videoDuration", ((ZIMVideoMessage) message).getVideoDuration());
                messageMap.putString(
                    "videoFirstFrameDownloadUrl",
                    ((ZIMVideoMessage) message).getVideoFirstFrameDownloadUrl()
                );
                messageMap.putString(
                    "videoFirstFrameLocalPath",
                    ((ZIMVideoMessage) message).getVideoFirstFrameLocalPath()
                );
                messageMap.putInt("videoFirstFrameWidth", ((ZIMVideoMessage) message).getVideoFirstFrameWidth());
                messageMap.putInt("videoFirstFrameHeight", ((ZIMVideoMessage) message).getVideoFirstFrameHeight());
                break;
            case AUDIO:
                assert message instanceof ZIMAudioMessage;
                messageMap.putDouble("audioDuration", ((ZIMAudioMessage) message).getAudioDuration());
                break;
            case FILE:
                assert message instanceof ZIMFileMessage;
                break;
            case MULTIPLE:
                assert message instanceof ZIMMultipleMessage;
                WritableArray infosArray = Arguments.createArray();
                for (ZIMMessageLiteInfo info : ((ZIMMultipleMessage) message).getMessageInfoList()) {
                    infosArray.pushMap(mZIMMessageLiteInfo(info));
                }
                messageMap.putArray("messageInfoList", infosArray);

                messageMap.putArray("failedIndexList", mIntArray(((ZIMMultipleMessage) message).getFailedIndexList()));
                break;
            default:
                break;
        }

        if (message instanceof ZIMMediaMessage) {
            messageMap.putString("fileLocalPath", ((ZIMMediaMessage) message).getFileLocalPath());
            messageMap.putString("fileDownloadUrl", ((ZIMMediaMessage) message).getFileDownloadUrl());
            messageMap.putString("fileUID", ((ZIMMediaMessage) message).getFileUID());
            messageMap.putString("fileName", ((ZIMMediaMessage) message).getFileName());
            messageMap.putDouble("fileSize", ((ZIMMediaMessage) message).getFileSize());
        }

        return messageMap;
    }

    public static ReadableArray mZIMMessageList(ArrayList<ZIMMessage> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMMessage info : infos) {
            array.pushMap(mZIMMessage(info));
        }

        return array;
    }

    public static ArrayList<ZIMMessage> oZIMMessageList(ReadableArray infos) {
        ArrayList<ZIMMessage> array = new ArrayList<>();

        if (infos != null) {
            for (Object obj : infos.toArrayList()) {
                array.add(oZIMMessage((HashMap<String, Object>) obj));
            }
        }

        return array;
    }

    public static WritableMap mZIMMessageLiteInfo(ZIMMessageLiteInfo message) {
        if (message == null) {
            return null;
        }

        WritableMap messageMap = Arguments.createMap();
        messageMap.putInt("type", message.type.value());

        switch (message.type) {
            case TEXT:
                assert message instanceof ZIMTextMessageLiteInfo;
                messageMap.putString("message", ((ZIMTextMessageLiteInfo) message).message);
                break;
            case CUSTOM:
                assert message instanceof ZIMCustomMessageLiteInfo;
                messageMap.putString("message", ((ZIMCustomMessageLiteInfo) message).message);
                messageMap.putInt("subType", ((ZIMCustomMessageLiteInfo) message).subType);
                messageMap.putString("searchedContent", ((ZIMCustomMessageLiteInfo) message).searchedContent);
                break;
            case COMBINE:
                assert message instanceof ZIMCombineMessageLiteInfo;
                messageMap.putString("title", ((ZIMCombineMessageLiteInfo) message).title);
                messageMap.putString("summary", ((ZIMCombineMessageLiteInfo) message).summary);
                break;
            case IMAGE:
                assert message instanceof ZIMImageMessageLiteInfo;

                messageMap.putString("thumbnailDownloadUrl", ((ZIMImageMessageLiteInfo) message).thumbnailDownloadUrl);
                messageMap.putString("thumbnailLocalPath", ((ZIMImageMessageLiteInfo) message).thumbnailLocalPath);
                messageMap.putString(
                    "largeImageDownloadUrl",
                    ((ZIMImageMessageLiteInfo) message).largeImageDownloadUrl
                );
                messageMap.putString("largeImageLocalPath", ((ZIMImageMessageLiteInfo) message).largeImageLocalPath);
                messageMap.putInt("originalImageWidth", ((ZIMImageMessageLiteInfo) message).originalImageWidth);
                messageMap.putInt("originalImageHeight", ((ZIMImageMessageLiteInfo) message).originalImageHeight);
                messageMap.putInt("thumbnailWidth", ((ZIMImageMessageLiteInfo) message).thumbnailWidth);
                messageMap.putInt("thumbnailHeight", ((ZIMImageMessageLiteInfo) message).thumbnailHeight);
                messageMap.putInt("largeImageWidth", ((ZIMImageMessageLiteInfo) message).largeImageWidth);
                messageMap.putInt("largeImageHeight", ((ZIMImageMessageLiteInfo) message).largeImageHeight);
                break;
            case VIDEO:
                assert message instanceof ZIMVideoMessageLiteInfo;

                messageMap.putDouble("videoDuration", ((ZIMVideoMessageLiteInfo) message).videoDuration);
                messageMap.putString(
                    "videoFirstFrameDownloadUrl",
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameDownloadUrl
                );
                messageMap.putString(
                    "videoFirstFrameLocalPath",
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameLocalPath
                );
                messageMap.putInt("videoFirstFrameWidth", ((ZIMVideoMessageLiteInfo) message).videoFirstFrameWidth);
                messageMap.putInt("videoFirstFrameHeight", ((ZIMVideoMessageLiteInfo) message).videoFirstFrameHeight);
                break;
            case AUDIO:
                assert message instanceof ZIMAudioMessageLiteInfo;
                messageMap.putDouble("audioDuration", ((ZIMAudioMessageLiteInfo) message).audioDuration);
                break;
            case MULTIPLE:
                assert message instanceof ZIMMultipleMessageLiteInfo;
                WritableArray infosArray = Arguments.createArray();
                for (ZIMMessageLiteInfo info : ((ZIMMultipleMessageLiteInfo) message).messageInfoList) {
                    infosArray.pushMap(mZIMMessageLiteInfo(info));
                }
                messageMap.putArray("messageInfoList", infosArray);
                break;
            default:
                break;
        }

        if (message instanceof ZIMMediaMessageLiteInfo) {
            messageMap.putString("fileLocalPath", ((ZIMMediaMessageLiteInfo) message).fileLocalPath);
            messageMap.putString("fileDownloadUrl", ((ZIMMediaMessageLiteInfo) message).fileDownloadUrl);
            messageMap.putString("fileName", ((ZIMMediaMessageLiteInfo) message).fileName);
            messageMap.putDouble("fileSize", ((ZIMMediaMessageLiteInfo) message).fileSize);
        }

        return messageMap;
    }

    public static ZIMMessageLiteInfo oZIMMessageLiteInfo(HashMap<String, Object> messageMap) {
        if (messageMap == null) {
            return null;
        }

        ZIMMessageLiteInfo message = null;
        ZIMMessageType type = ZIMMessageType.getZIMMessageType(
            Double.valueOf((double) messageMap.get("type")).intValue()
        );
        switch (type) {
            case TEXT:
                message = new ZIMTextMessageLiteInfo();
                ((ZIMTextMessageLiteInfo) message).message = (String) messageMap.get("message");
                break;
            case REVOKE:
                message = new ZIMRevokeMessageLiteInfo();
                break;
            case CUSTOM:
                message = new ZIMCustomMessageLiteInfo();
                if (messageMap.containsKey("subType")) {
                    ((ZIMCustomMessageLiteInfo) message).subType = Double.valueOf(
                        (double) messageMap.get("subType")
                    ).intValue();
                }
                if (messageMap.containsKey("message")) {
                    ((ZIMCustomMessageLiteInfo) message).message = (String) messageMap.get("message");
                }
                if (messageMap.containsKey("searchedContent")) {
                    ((ZIMCustomMessageLiteInfo) message).searchedContent = (String) messageMap.get("searchedContent");
                }
                break;
            case COMBINE:
                message = new ZIMCombineMessageLiteInfo();
                if (messageMap.containsKey("title")) {
                    ((ZIMCombineMessageLiteInfo) message).title = (String) messageMap.get("title");
                }
                if (messageMap.containsKey("summary")) {
                    ((ZIMCombineMessageLiteInfo) message).summary = (String) messageMap.get("summary");
                }
                break;
            case IMAGE:
                message = new ZIMImageMessageLiteInfo();
                if (messageMap.containsKey("originalImageWidth")) {
                    ((ZIMImageMessageLiteInfo) message).originalImageWidth = Double.valueOf(
                        (double) messageMap.get("originalImageWidth")
                    ).intValue();
                }
                if (messageMap.containsKey("originalImageHeight")) {
                    ((ZIMImageMessageLiteInfo) message).originalImageHeight = Double.valueOf(
                        (double) messageMap.get("originalImageHeight")
                    ).intValue();
                }
                if (messageMap.containsKey("thumbnailWidth")) {
                    ((ZIMImageMessageLiteInfo) message).thumbnailWidth = Double.valueOf(
                        (double) messageMap.get("thumbnailWidth")
                    ).intValue();
                }
                if (messageMap.containsKey("thumbnailHeight")) {
                    ((ZIMImageMessageLiteInfo) message).thumbnailHeight = Double.valueOf(
                        (double) messageMap.get("thumbnailHeight")
                    ).intValue();
                }
                if (messageMap.containsKey("largeImageWidth")) {
                    ((ZIMImageMessageLiteInfo) message).largeImageWidth = Double.valueOf(
                        (double) messageMap.get("largeImageWidth")
                    ).intValue();
                }
                if (messageMap.containsKey("largeImageHeight")) {
                    ((ZIMImageMessageLiteInfo) message).largeImageHeight = Double.valueOf(
                        (double) messageMap.get("largeImageHeight")
                    ).intValue();
                }
                if (messageMap.containsKey("thumbnailDownloadUrl")) {
                    ((ZIMImageMessageLiteInfo) message).thumbnailDownloadUrl = (String) messageMap.get(
                        "thumbnailDownloadUrl"
                    );
                }
                if (messageMap.containsKey("thumbnailLocalPath")) {
                    ((ZIMImageMessageLiteInfo) message).thumbnailLocalPath = (String) messageMap.get(
                        "thumbnailLocalPath"
                    );
                }
                if (messageMap.containsKey("largeImageDownloadUrl")) {
                    ((ZIMImageMessageLiteInfo) message).largeImageDownloadUrl = (String) messageMap.get(
                        "largeImageDownloadUrl"
                    );
                }
                if (messageMap.containsKey("largeImageLocalPath")) {
                    ((ZIMImageMessageLiteInfo) message).largeImageLocalPath = (String) messageMap.get(
                        "largeImageLocalPath"
                    );
                }
                break;
            case FILE:
                message = new ZIMFileMessageLiteInfo();
                break;
            case VIDEO:
                message = new ZIMVideoMessageLiteInfo();
                if (messageMap.containsKey("videoFirstFrameDownloadUrl")) {
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameDownloadUrl = (String) messageMap.get(
                        "videoFirstFrameDownloadUrl"
                    );
                }
                if (messageMap.containsKey("videoFirstFrameLocalPath")) {
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameLocalPath = (String) messageMap.get(
                        "videoFirstFrameLocalPath"
                    );
                }
                if (messageMap.containsKey("videoDuration")) {
                    ((ZIMVideoMessageLiteInfo) message).videoDuration = Double.valueOf(
                        (double) messageMap.get("videoDuration")
                    ).longValue();
                }
                if (messageMap.containsKey("videoFirstFrameWidth")) {
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameWidth = Double.valueOf(
                        (double) messageMap.get("videoFirstFrameWidth")
                    ).intValue();
                }
                if (messageMap.containsKey("videoFirstFrameHeight")) {
                    ((ZIMVideoMessageLiteInfo) message).videoFirstFrameHeight = Double.valueOf(
                        (double) messageMap.get("videoFirstFrameHeight")
                    ).intValue();
                }
                break;
            case AUDIO:
                message = new ZIMAudioMessageLiteInfo();
                if (messageMap.containsKey("audioDuration")) {
                    ((ZIMAudioMessageLiteInfo) message).audioDuration = Double.valueOf(
                        (double) messageMap.get("audioDuration")
                    ).longValue();
                }
                break;
            case MULTIPLE:
                message = new ZIMMultipleMessageLiteInfo();
                if (messageMap.get("messageInfoList") != null) {
                    ArrayList<ZIMMessageLiteInfo> messageInfoList = new ArrayList<>();
                    for (Object messageObj : (ArrayList) messageMap.get("messageInfoList")) {
                        messageInfoList.add(oZIMMessageLiteInfo((HashMap<String, Object>) messageObj));
                    }
                    ((ZIMMultipleMessageLiteInfo) message).messageInfoList = messageInfoList;
                }
                break;
            default:
                message = new ZIMMessageLiteInfo();
                break;
        }

        if (message instanceof ZIMMediaMessageLiteInfo) {
            if (messageMap.containsKey("fileSize")) {
                ((ZIMMediaMessageLiteInfo) message).fileSize = Double.valueOf(
                    (double) messageMap.get("fileSize")
                ).longValue();
            }
            if (messageMap.containsKey("fileName")) {
                ((ZIMMediaMessageLiteInfo) message).fileName = (String) messageMap.get("fileName");
            }
            if (messageMap.containsKey("fileDownloadUrl")) {
                ((ZIMMediaMessageLiteInfo) message).fileDownloadUrl = (String) messageMap.get("fileDownloadUrl");
            }
            if (messageMap.containsKey("fileLocalPath")) {
                ((ZIMMediaMessageLiteInfo) message).fileLocalPath = (String) messageMap.get("fileLocalPath");
            }
        }

        return message;
    }

    public static WritableMap mZIMMessageRepliedInfo(ZIMMessageRepliedInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("state", info.state.value());
        map.putDouble("messageSeq", info.messageSeq);
        map.putString("messageID", String.valueOf(info.messageID));
        map.putString("senderUserID", info.senderUserID);
        map.putDouble("sentTime", info.sentTime);

        ZIMMessageLiteInfo message = info.messageInfo;
        if (message == null) {
            map.putNull("messageInfo");
            return map;
        }

        map.putMap("messageInfo", mZIMMessageLiteInfo(message));
        return map;
    }

    public static ReadableMap mZIMTipsMessageChangeInfo(ZIMTipsMessageChangeInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());

        if (info instanceof ZIMTipsMessageGroupChangeInfo) {
            map.putInt("groupDataFlag", ((ZIMTipsMessageGroupChangeInfo) info).groupDataFlag);
            map.putString("groupName", ((ZIMTipsMessageGroupChangeInfo) info).groupName);
            map.putString("groupNotice", ((ZIMTipsMessageGroupChangeInfo) info).groupNotice);
            map.putString("groupAvatarUrl", ((ZIMTipsMessageGroupChangeInfo) info).groupAvatarUrl);
            map.putMap("groupMutedInfo", mZIMGroupMuteInfo(((ZIMTipsMessageGroupChangeInfo) info).groupMutedInfo));
        } else if (info instanceof ZIMTipsMessageGroupMemberChangeInfo) {
            map.putInt("memberRole", ((ZIMTipsMessageGroupMemberChangeInfo) info).memberRole);
            map.putDouble("muteExpiredTime", ((ZIMTipsMessageGroupMemberChangeInfo) info).muteExpiredTime);
            map.putMap(
                "groupNewOwner",
                mSuperZIMGroupMemberSimpleInfo(((ZIMTipsMessageGroupMemberChangeInfo) info).groupNewOwner)
            );
        } else if (info instanceof ZIMTipsMessagePinStatusChangeInfo) {
            map.putBoolean("isPinned", ((ZIMTipsMessagePinStatusChangeInfo) info).isPinned);
        }

        return map;
    }

    public static ZIMTipsMessageChangeInfo oZIMTipsMessageChangeInfo(ReadableMap map) {
        if (map == null) {
            return null;
        }

        ZIMTipsMessageChangeInfo info = null;
        ZIMTipsMessageChangeInfoType type = ZIMTipsMessageChangeInfoType.getZIMTipsMessageChangeInfoType(
            map.getInt("type")
        );
        switch (type) {
            case GROUP_DATA_CHANGED:
            case GROUP_NOTICE_CHANGED:
            case GROUP_NAME_CHANGED:
            case GROUP_AVATAR_URL_CHANGED:
            case GROUP_MUTE_CHANGED:
                info = new ZIMTipsMessageGroupChangeInfo();
                break;
            case GROUP_OWNER_TRANSFERRED:
            case GROUP_MEMBER_ROLE_CHANGED:
            case GROUP_MEMBER_MUTE_CHANGED:
                info = new ZIMTipsMessageGroupMemberChangeInfo();
                break;
            default:
                info = new ZIMTipsMessageChangeInfo();
                break;
        }

        return info;
    }

    public static ZIMTipsMessageChangeInfo oZIMTipsMessageChangeInfo(HashMap<String, Object> map) {
        if (map == null) {
            return null;
        }

        ZIMTipsMessageChangeInfo info = null;
        ZIMTipsMessageChangeInfoType type = ZIMTipsMessageChangeInfoType.getZIMTipsMessageChangeInfoType(
            Double.valueOf((double) map.get("type")).intValue()
        );
        switch (type) {
            case GROUP_DATA_CHANGED:
            case GROUP_NOTICE_CHANGED:
            case GROUP_NAME_CHANGED:
            case GROUP_AVATAR_URL_CHANGED:
            case GROUP_MUTE_CHANGED:
                info = new ZIMTipsMessageGroupChangeInfo();
                break;
            case GROUP_OWNER_TRANSFERRED:
            case GROUP_MEMBER_ROLE_CHANGED:
            case GROUP_MEMBER_MUTE_CHANGED:
                info = new ZIMTipsMessageGroupMemberChangeInfo();
                break;
            default:
                info = new ZIMTipsMessageChangeInfo();
                break;
        }

        return info;
    }

    public static ReadableMap mZIMRoomFullInfo(ZIMRoomFullInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap baseInfoMap = Arguments.createMap();
        baseInfoMap.putString("roomID", info.baseInfo.roomID);
        baseInfoMap.putString("roomName", info.baseInfo.roomName);

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", baseInfoMap);
        return map;
    }

    public static ReadableMap mZIMGroupMuteInfo(ZIMGroupMuteInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("mode", info.mode.value());
        map.putDouble("expiredTime", info.expiredTime);
        map.putArray("roles", mIntArray(info.roles));

        return map;
    }

    public static ReadableMap mZIMCommunityChannelMuteInfo(ZIMCommunityChannelMuteInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("mode", info.getMode().value());
        map.putDouble("expiredTime", info.getExpiredTime());
        map.putArray("roles", mIntArray(info.getRoles()));

        return map;
    }

    public static ReadableMap mZIMGroupVerifyInfo(ZIMGroupVerifyInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("joinMode", info.joinMode.value());
        map.putInt("inviteMode", info.inviteMode.value());
        map.putInt("beInviteMode", info.beInviteMode.value());

        return map;
    }

    public static ReadableMap mZIMGroupInfo(ZIMGroupInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("groupID", info.groupID);
        map.putString("groupName", info.groupName);
        map.putString("groupAvatarUrl", info.groupAvatarUrl);

        return map;
    }

    public static ReadableMap mZIMGroupFullInfo(ZIMGroupFullInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMGroupInfo(info.baseInfo));
        map.putString("groupAlias", info.groupAlias);
        map.putString("groupNotice", info.groupNotice);
        map.putMap("groupAttributes", mMap(info.groupAttributes));
        map.putInt("notificationStatus", info.notificationStatus.value());
        map.putInt("maxMemberCount", info.maxMemberCount);
        map.putDouble("createTime", info.createTime);
        map.putMap("mutedInfo", mZIMGroupMuteInfo(info.mutedInfo));
        map.putMap("verifyInfo", mZIMGroupVerifyInfo(info.verifyInfo));

        return map;
    }

    public static ReadableMap mZIMCommunityInfo(ZIMCommunityInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("communityID", info.getCommunityID());
        map.putString("communityName", info.getCommunityName());
        map.putString("communityAvatarUrl", info.getCommunityAvatarUrl());

        return map;
    }

    public static ReadableMap mZIMCommunity(ZIMCommunity info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMCommunityInfo(info.getBaseInfo()));
        map.putInt("totalUnreadMessageCount", info.getTotalUnreadMessageCount());

        return map;
    }

    public static ReadableMap mZIMCommunityFullInfo(ZIMCommunityFullInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMCommunityInfo(info.getBaseInfo()));
        map.putString("communityNotice", info.getCommunityNotice());
        map.putMap("communityAttributes", mMap(info.getCommunityAttributes()));
        map.putInt("notificationStatus", info.getNotificationStatus().value());
        map.putInt("currentMemberCount", info.getCurrentMemberCount());
        map.putDouble("createTime", info.getCreateTime());
        map.putString("creatorUserID", info.getCreatorUserID());

        return map;
    }

    public static ReadableArray mZIMCommunityChangeInfoList(ArrayList<ZIMCommunityChangeInfo> infos) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityChangeInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putInt("action", info.getAction().value());
            map.putMap("community", mZIMCommunity(info.getCommunity()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCommunityFullInfoUpdateInfoList(ArrayList<ZIMCommunityFullInfoUpdateInfo> infos) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityFullInfoUpdateInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putMap("communityInfo", mZIMCommunityFullInfo(info.getCommunityInfo()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCommunityMemberStateChangeInfoList(
        ArrayList<ZIMCommunityMemberStateChangeInfo> infos
    ) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityMemberStateChangeInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putInt("state", info.getState().value());
            map.putInt("action", info.getAction().value());
            map.putMap("memberInfo", mZIMCommunityMemberSimpleInfo(info.getMemberInfo()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCommunityMemberInfoUpdateInfoList(
        ArrayList<ZIMCommunityMemberInfoUpdateInfo> infos
    ) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityMemberInfoUpdateInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putMap("memberInfo", mZIMCommunityMemberInfo(info.getMemberInfo()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCommunityChannelChangeInfoList(ArrayList<ZIMCommunityChannelChangeInfo> infos) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityChannelChangeInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putInt("action", info.getAction().value());
            map.putMap("channel", mZIMCommunityChannel(info.getChannel()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCommunityChannelFullInfoUpdateInfoList(
        ArrayList<ZIMCommunityChannelFullInfoUpdateInfo> infos
    ) {
        WritableArray array = Arguments.createArray();
        for (ZIMCommunityChannelFullInfoUpdateInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putMap("channelInfo", mZIMCommunityChannelFullInfo(info.getChannelInfo()));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableMap mZIMCommunityChannelInfo(ZIMCommunityChannelInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("communityID", info.getCommunityID());
        map.putInt("channelType", info.getChannelType().value());
        map.putString("channelID", info.getChannelID());
        map.putString("channelName", info.getChannelName());
        map.putString("channelAvatarUrl", info.getChannelAvatarUrl());

        return map;
    }

    public static ReadableMap mZIMCommunityChannel(ZIMCommunityChannel info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMCommunityChannelInfo(info.getBaseInfo()));
        map.putString("conversationID", info.getConversationID());
        map.putMap("channelAttributes", mMap(info.getChannelAttributes()));
        map.putInt("unreadMessageCount", info.getUnreadMessageCount());
        map.putInt("notificationStatus", info.getNotificationStatus().value());
        map.putDouble("selfMutedExpiredTime", info.getSelfMutedExpiredTime());
        map.putString("draft", info.getDraft());

        if (info.getLastMessage() != null) {
            map.putMap("lastMessage", mZIMMessage(info.getLastMessage()));
        } else {
            map.putNull("lastMessage");
        }
        if (info.getMentionedInfoList() != null) {
            map.putArray("mentionedInfoList", mZIMMessageMentionedInfoList(info.getMentionedInfoList()));
        }

        return map;
    }

    public static ReadableMap mZIMCommunityChannelFullInfo(ZIMCommunityChannelFullInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("baseInfo", mZIMCommunityChannelInfo(info.getBaseInfo()));
        map.putString("channelNotice", info.getChannelNotice());
        map.putMap("channelAttributes", mMap(info.getChannelAttributes()));
        map.putInt("currentMemberCount", info.getCurrentMemberCount());
        map.putDouble("createTime", info.getCreateTime());
        map.putString("creatorUserID", info.getCreatorUserID());

        if (info.getMuteInfo() != null) {
            map.putMap("muteInfo", mZIMCommunityChannelMuteInfo(info.getMuteInfo()));
        }

        return map;
    }

    public static ReadableArray mZIMCommunityChannelFullInfoList(ArrayList<ZIMCommunityChannelFullInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMCommunityChannelFullInfo info : infos) {
            array.pushMap(mZIMCommunityChannelFullInfo(info));
        }

        return array;
    }

    public static ReadableArray mZIMCommunityChannelList(ArrayList<ZIMCommunityChannel> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMCommunityChannel info : infos) {
            array.pushMap(mZIMCommunityChannel(info));
        }

        return array;
    }

    public static ReadableMap mZIMGroupMemberInfo(ZIMGroupMemberInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        map.putInt("memberRole", info.memberRole);
        map.putString("memberNickname", info.memberNickname);
        map.putDouble("muteExpiredTime", info.muteExpiredTime);

        if (info.groupEnterInfo != null) {
            WritableMap enterInfoMap = Arguments.createMap();
            enterInfoMap.putDouble("enterTime", info.groupEnterInfo.enterTime);
            enterInfoMap.putInt("enterType", info.groupEnterInfo.enterType.value());
            enterInfoMap.putMap("operatedUser", mZIMGroupMemberSimpleInfo(info.groupEnterInfo.operatedUser));
            map.putMap("groupEnterInfo", enterInfoMap);
        }

        return map;
    }

    public static ReadableMap mZIMCommunityMemberInfo(ZIMCommunityMemberInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        map.putInt("memberRole", info.getMemberRole());

        if (info.getEnterInfo() != null) {
            WritableMap enterInfoMap = Arguments.createMap();
            enterInfoMap.putDouble("enterTime", info.getEnterInfo().getEnterTime());
            enterInfoMap.putInt("enterType", info.getEnterInfo().getEnterType().value());
            enterInfoMap.putString("operatedUserID", info.getEnterInfo().getOperatedUserID());
            map.putMap("enterInfo", enterInfoMap);
        }

        if (info.getMuteInfo() != null) {
            WritableMap muteInfoMap = Arguments.createMap();
            muteInfoMap.putDouble("muteExpiredTime", info.getMuteInfo().getMuteExpiredTime());
            muteInfoMap.putInt("muteType", info.getMuteInfo().getMuteType().value());
            muteInfoMap.putString("channelID", info.getMuteInfo().getChannelID());
            map.putMap("muteInfo", muteInfoMap);
        }

        return map;
    }

    public static ReadableMap mZIMCommunityMemberSimpleInfo(ZIMCommunityMemberSimpleInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        map.putInt("memberRole", info.getMemberRole());

        return map;
    }

    public static ReadableMap mSuperZIMGroupMemberSimpleInfo(ZIMUserInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        if (info instanceof ZIMGroupMemberSimpleInfo) {
            map.putInt("memberRole", ((ZIMGroupMemberSimpleInfo) info).memberRole);
            map.putString("memberNickname", ((ZIMGroupMemberSimpleInfo) info).memberNickname);
        }

        return map;
    }

    public static ZIMUserInfo oSuperZIMGroupMemberSimpleInfo(ReadableMap map) {
        if (map == null) {
            return null;
        }

        ZIMUserInfo info = map.hasKey("memberRole") ? new ZIMGroupMemberSimpleInfo() : new ZIMUserInfo();
        info.type = ZIMUserInfoType.getEnum(map.hasKey("type") ? map.getInt("type") : 1);
        info.userID = map.hasKey("userID") ? map.getString("userID") : "";
        info.userName = map.hasKey("userName") ? map.getString("userName") : "";
        info.userAvatarUrl = map.hasKey("userAvatarUrl") ? map.getString("userAvatarUrl") : "";
        info.userExtendedData = map.hasKey("userExtendedData") ? map.getString("userExtendedData") : "";

        if (info instanceof ZIMGroupMemberSimpleInfo) {
            ((ZIMGroupMemberSimpleInfo) info).memberRole = map.getInt("memberRole");
            ((ZIMGroupMemberSimpleInfo) info).memberNickname = map.hasKey("memberNickname")
                ? map.getString("memberNickname")
                : "";
        }

        return info;
    }

    public static ZIMUserInfo oSuperZIMGroupMemberSimpleInfo(HashMap<String, Object> map) {
        if (map == null) {
            return null;
        }

        ZIMUserInfo info = map.containsKey("memberRole") ? new ZIMGroupMemberSimpleInfo() : new ZIMUserInfo();

        info.type = ZIMUserInfoType.getEnum(
            map.containsKey("type") ? Double.valueOf((double) map.get("type")).intValue() : 1
        );
        info.userID = map.containsKey("userID") ? (String) map.get("userID") : "";
        info.userName = map.containsKey("userName") ? (String) map.get("userName") : "";
        info.userAvatarUrl = map.containsKey("userAvatarUrl") ? (String) map.get("userAvatarUrl") : "";
        info.userExtendedData = map.containsKey("userExtendedData") ? (String) map.get("userExtendedData") : "";

        if (info instanceof ZIMGroupMemberSimpleInfo) {
            ((ZIMGroupMemberSimpleInfo) info).memberRole = map.containsKey("memberRole")
                ? Double.valueOf((double) map.get("memberRole")).intValue()
                : 0;
            ((ZIMGroupMemberSimpleInfo) info).memberNickname = map.containsKey("memberNickname")
                ? (String) map.get("memberNickname")
                : "";
        }

        return info;
    }

    public static ReadableArray mSuperZIMGroupMemberSimpleInfoList(ArrayList<ZIMUserInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMUserInfo info : infos) {
            array.pushMap(mSuperZIMGroupMemberSimpleInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMGroupMemberSimpleInfo(ZIMGroupMemberSimpleInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);
        
        map.putInt("memberRole", info.memberRole);
        map.putString("memberNickname", info.memberNickname);

        return map;
    }

    public static ReadableArray mZIMGroupMemberInfoList(ArrayList<ZIMGroupMemberInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMGroupMemberInfo info : infos) {
            array.pushMap(mZIMGroupMemberInfo(info));
        }

        return array;
    }

    public static ReadableArray mZIMCommunityMemberInfoList(ArrayList<ZIMCommunityMemberInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMCommunityMemberInfo info : infos) {
            array.pushMap(mZIMCommunityMemberInfo(info));
        }

        return array;
    }

    public static ReadableArray mZIMGroupList(ArrayList<ZIMGroup> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMGroup info : infos) {
            WritableMap map = Arguments.createMap();
            map.putMap("baseInfo", mZIMGroupInfo(info.baseInfo));
            map.putString("groupAlias", info.groupAlias);
            map.putInt("notificationStatus", info.notificationStatus.value());

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMCallUserInfoList(ArrayList<ZIMCallUserInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMCallUserInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putString("userID", info.userID);
            map.putInt("state", info.state.value());
            map.putString("extendedData", info.extendedData);

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableArray mZIMConversationChangeInfoList(ArrayList<ZIMConversationChangeInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMConversationChangeInfo info : infos) {
            WritableMap map = Arguments.createMap();
            map.putInt("event", info.event.value());
            map.putInt("action", info.action.value());
            map.putMap("conversation", mZIMConversation(info.conversation));

            array.pushMap(map);
        }

        return array;
    }

    public static ReadableMap mZIMGroupOperatedInfo(ZIMGroupOperatedInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putInt("memberRole", info.memberRole);
        map.putString("memberNickname", info.memberNickname);

        return map;
    }

    public static ReadableMap mZIMRoomMemberAttributesInfo(ZIMRoomMemberAttributesInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("userID", info.userID);
        map.putMap("attributes", mMap(info.attributes));

        return map;
    }

    public static ReadableArray mZIMRoomMemberAttributesInfoList(ArrayList<ZIMRoomMemberAttributesInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMRoomMemberAttributesInfo info : infos) {
            array.pushMap(mZIMRoomMemberAttributesInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMRoomMemberAttributesOperatedInfo(ZIMRoomMemberAttributesOperatedInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("attributesInfo", mZIMRoomMemberAttributesInfo(info.attributesInfo));
        map.putArray("errorKeys", mStringArray(info.errorKeys));

        return map;
    }

    public static ReadableArray mZIMRoomMemberAttributesOperatedInfoList(
        ArrayList<ZIMRoomMemberAttributesOperatedInfo> infos
    ) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMRoomMemberAttributesOperatedInfo info : infos) {
            array.pushMap(mZIMRoomMemberAttributesOperatedInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMRoomMemberAttributesUpdateInfo(ZIMRoomMemberAttributesUpdateInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putMap("attributesInfo", mZIMRoomMemberAttributesInfo(info.attributesInfo));

        return map;
    }

    public static ReadableArray mZIMRoomMemberAttributesUpdateInfoList(
        ArrayList<ZIMRoomMemberAttributesUpdateInfo> infos
    ) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMRoomMemberAttributesUpdateInfo info : infos) {
            array.pushMap(mZIMRoomMemberAttributesUpdateInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMRoomOperatedInfo(ZIMRoomOperatedInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putString("userID", info.userID);

        return map;
    }

    public static ReadableMap mZIMFriendInfo(ZIMFriendInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putString("userID", info.userID);
        map.putString("userName", info.userName);
        map.putString("userAvatarUrl", info.userAvatarUrl);
        map.putString("userExtendedData", info.userExtendedData);

        map.putString("wording", info.wording);
        map.putString("friendAlias", info.friendAlias);
        map.putDouble("createTime", info.createTime);
        map.putMap("friendAttributes", mMap(info.friendAttributes));

        return map;
    }

    public static ReadableArray mZIMFriendInfoList(ArrayList<ZIMFriendInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMFriendInfo info : infos) {
            array.pushMap(mZIMFriendInfo(info));
        }

        return array;
    }

    public static ReadableMap mZIMFriendApplicationInfo(ZIMFriendApplicationInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putInt("state", info.state.value());
        map.putString("wording", info.wording);
        map.putDouble("createTime", info.createTime);
        map.putDouble("updateTime", info.updateTime);
        map.putMap("applyUser", mZIMUserInfo(info.applyUser));

        return map;
    }

    public static ReadableMap mZIMGroupApplicationInfo(ZIMGroupApplicationInfo info) {
        if (info == null) {
            return null;
        }

        WritableMap map = Arguments.createMap();
        map.putInt("type", info.type.value());
        map.putInt("state", info.state.value());
        map.putString("wording", info.wording);
        map.putDouble("createTime", info.createTime);
        map.putDouble("updateTime", info.updateTime);
        map.putMap("applyUser", mZIMUserInfo(info.applyUser));
        map.putMap("groupInfo", mZIMGroupInfo(info.groupInfo));
        map.putMap("operatedUser", mZIMGroupMemberSimpleInfo(info.operatedUser));

        return map;
    }

    public static ReadableArray mZIMFriendApplicationInfoList(ArrayList<ZIMFriendApplicationInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMFriendApplicationInfo info : infos) {
            array.pushMap(mZIMFriendApplicationInfo(info));
        }

        return array;
    }

    public static ReadableArray mZIMGroupApplicationInfoList(ArrayList<ZIMGroupApplicationInfo> infos) {
        if (infos == null) {
            return null;
        }

        WritableArray array = Arguments.createArray();
        for (ZIMGroupApplicationInfo info : infos) {
            array.pushMap(mZIMGroupApplicationInfo(info));
        }

        return array;
    }
}
