package com.chatsdk.dispatch;

import static io.agora.Error.GENERAL_ERROR;

import android.text.TextUtils;
import com.chatsdk.common.ExtSdkCallback;
import io.agora.chat.ChatClient;
import io.agora.chat.Conversation;
import io.agora.chat.ChatMessage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class ExtSdkConversationWrapper extends ExtSdkWrapper {

    public static class SingleHolder {
        static ExtSdkConversationWrapper instance = new ExtSdkConversationWrapper();
    }

    public static ExtSdkConversationWrapper getInstance() { return ExtSdkConversationWrapper.SingleHolder.instance; }

    ExtSdkConversationWrapper() {}

    public void getUnreadMsgCount(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        onSuccess(result, channelName, conversation.getUnreadMsgCount());
    }

    public void getMsgCount(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        onSuccess(result, channelName, conversation.getAllMsgCount());
    }

    public void markAllMessagesAsRead(JSONObject params, String channelName, ExtSdkCallback result)
        throws JSONException {
        Conversation conversation = this.getConversation(params);
        conversation.markAllMessagesAsRead();
        onSuccess(result, channelName, null);
    }

    public void markMessageAsRead(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        String msg_id = params.getString("msg_id");
        conversation.markMessageAsRead(msg_id);
        onSuccess(result, channelName, null);
    }

    public void syncConversationExt(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        JSONObject ext = params.getJSONObject("ext");
        String jsonStr = "";
        if (ext.length() != 0) {
            jsonStr = ext.toString();
        }
        conversation.setExtField(jsonStr);
        onSuccess(result, channelName, null);
    }

    public void removeMessage(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        String msg_id = params.getString("msg_id");
        conversation.removeMessage(msg_id);
        onSuccess(result, channelName, null);
    }

    public void getLatestMessage(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        ChatMessage msg = conversation.getLastMessage();
        onSuccess(result, channelName, ExtSdkMessageHelper.toJson(msg));
    }

    public void getLatestMessageFromOthers(JSONObject params, String channelName, ExtSdkCallback result)
        throws JSONException {
        Conversation conversation = this.getConversation(params);
        ChatMessage msg = conversation.getLatestMessageFromOthers();
        onSuccess(result, channelName, ExtSdkMessageHelper.toJson(msg));
    }

    public void clearAllMessages(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        conversation.clearAllMessages();
        onSuccess(result, channelName, null);
    }

    public void deleteMessagesWithTimestamp(JSONObject params, String channelName, ExtSdkCallback result)
        throws JSONException {
        long startTs = params.getLong("startTs");
        long endTs = params.getLong("endTs");
        Conversation conversation = this.getConversation(params);
        boolean ret = conversation.removeMessages(startTs, endTs);
        if (ret == true) {
            onSuccess(result, channelName, null);
        } else {
            onError(result, GENERAL_ERROR, "remove local message is failed.");
        }
    }

    public void insertMessage(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        //        Conversation conversation = this.getConversation(params);
        JSONObject msg = params.getJSONObject("msg");
        ChatMessage message = ExtSdkMessageHelper.fromJson(msg);
        if (message != null) {
            final Conversation conversation = this.getConversationFromMessage(message);
            conversation.insertMessage(message);
        }
        onSuccess(result, channelName, null);
    }

    public void appendMessage(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        //        Conversation conversation = this.getConversation(params);
        JSONObject msg = params.getJSONObject("msg");
        ChatMessage message = ExtSdkMessageHelper.fromJson(msg);
        if (message != null) {
            final Conversation conversation = this.getConversationFromMessage(message);
            conversation.appendMessage(message);
        }
        onSuccess(result, channelName, null);
    }

    public void updateConversationMessage(JSONObject params, String channelName, ExtSdkCallback result)
        throws JSONException {
        Conversation conversation = this.getConversation(params);
        JSONObject msg = params.getJSONObject("msg");
        ChatMessage message = ExtSdkMessageHelper.fromJson(msg);
        ChatMessage dbMsg = ChatClient.getInstance().chatManager().getMessage(message.getMsgId());
        if (ExtSdkWrapper.checkMessageParams(dbMsg, channelName, result)) {
            return;
        }
        this.mergeMessage(message, dbMsg);
        conversation.updateMessage(dbMsg);
        onSuccess(result, channelName, null);
    }

    public void loadMsgWithId(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        String msgId = params.getString("msg_id");
        ChatMessage msg = ChatClient.getInstance().chatManager().getMessage(msgId);
        if (ExtSdkWrapper.getMessageParams(msg, channelName, result)) {
            return;
        }
        onSuccess(result, channelName, ExtSdkMessageHelper.toJson(msg));
    }

    public void loadMsgWithStartId(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        String startId = params.getString("startId");
        int pageSize = params.getInt("count");
        Conversation.SearchDirection direction = searchDirectionFromString(params.getString("direction"));
        List<ChatMessage> msgList = conversation.loadMoreMsgFromDB(startId, pageSize, direction);
        List<Map> messages = new ArrayList<>();
        for (ChatMessage msg : msgList) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }

    public void loadMsgWithKeywords(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        String keywords = params.getString("keywords");
        String sender = null;
        if (params.has("sender")) {
            sender = params.getString("sender");
        }
        final String name = sender;
        int count = params.getInt("count");
        long timestamp = params.getLong("timestamp");
        Conversation.SearchDirection direction = searchDirectionFromString(params.getString("direction"));
        Conversation.ChatMessageSearchScope scope;
        if (params.has("searchScope")) {
            scope = Conversation.ChatMessageSearchScope.values()[params.getInt("searchScope")];
        } else {
            scope = Conversation.ChatMessageSearchScope.ALL;
        }
        List<ChatMessage> msgList = conversation.searchMsgFromDB(keywords, timestamp, count, name, direction, scope);
        List<Map> messages = new ArrayList<>();
        for (ChatMessage msg : msgList) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }

    public void loadMsgWithMsgType(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        long timestamp = params.getLong("timestamp");
        String sender = params.getString("sender");
        int count = params.getInt("count");
        Conversation.SearchDirection direction = searchDirectionFromString(params.getString("direction"));
        String typeStr = params.getString("msg_type");
        ChatMessage.Type type = ExtSdkChatMessageTypeHelper.toType(typeStr);
        ChatMessage.Type finalType = type;
        List<ChatMessage> msgList = conversation.searchMsgFromDB(finalType, timestamp, count, sender, direction);
        List<Map> messages = new ArrayList<>();
        for (ChatMessage msg : msgList) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }

    public void loadMsgWithTime(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        long startTime = params.getLong("startTime");
        long endTime = params.getLong("endTime");
        int count = params.getInt("count");
        List<ChatMessage> msgList = conversation.searchMsgFromDB(startTime, endTime, count);
        List<Map> messages = new ArrayList<>();
        for (ChatMessage msg : msgList) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }

    public void pinnedMessages(JSONObject params, String channelName, ExtSdkCallback result) throws JSONException {
        Conversation conversation = this.getConversation(params);
        List<ChatMessage> msgList = conversation.pinnedMessages();
        List<Map> messages = new ArrayList<>();
        for (ChatMessage msg : msgList) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }

    public void searchMessages(JSONObject param, String channelName, ExtSdkCallback result) throws JSONException {
        JSONArray typesJson = param.getJSONArray("types");
        Set<ChatMessage.Type> types = new HashSet<>();
        for (int i = 0; i < typesJson.length(); i++) {
            String type = typesJson.getString(i);
            types.add(ExtSdkChatMessageTypeHelper.toType(type));
        }
        long timestamp = param.getLong("timestamp");
        int count = param.getInt("count");
        String from = param.getString("from");
        Conversation.SearchDirection direction =
            ExtSdkSearchDirectionHelper.toDirection(param.getString("direction"));
        Conversation conversation = this.getConversation(param);
        List<ChatMessage> msgs = conversation.searchMsgFromDB(types, timestamp, count, from, direction);
        List<Map<?, ?>> messages = new ArrayList<>();
        for (ChatMessage msg : msgs) {
            messages.add(ExtSdkMessageHelper.toJson(msg));
        }
        onSuccess(result, channelName, messages);
    }
    public void getMessageCountWithTimestamp(JSONObject param, String channelName, ExtSdkCallback result)
        throws JSONException {
        Conversation conversation = this.getConversation(param);
        long start = param.getLong("start");
        long end = param.getLong("end");
        int ret = conversation.getAllMsgCount(start, end);
        onSuccess(result, channelName, ret);
    }

    private Conversation.SearchDirection searchDirectionFromString(String direction) {
        return TextUtils.equals(direction, "up") ? Conversation.SearchDirection.UP
                                                 : Conversation.SearchDirection.DOWN;
    }
}
