package com.rv.im.xmpp;

import android.util.Log;

import com.rv.component.utils.CacheEnum;
import com.rv.component.utils.RvCache;
import com.rv.im.AppConfig;
import com.rv.im.ImService;
import com.rv.im.ImSetting;
import com.rv.im.db.table.ChatMessage;
import com.rv.im.util.ThreadManager;

import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;

import java.util.HashMap;
import java.util.Map;

/**
 * 功能：
 * 1、接收消息，包括单聊和群聊的接收消息的监听的绑定、具体处理已转移到 xChatlistener 和 xMucChatlistener
 * 2、发送消息，包括发送单聊和群聊的
 */
public class XChatManager {
    private ImService mService;
    private XMPPConnection mConnection;

    private String mLoginUserId;
    private String mServerName;

    private ChatManager mChatManager;
    private XChatMessageListener mMessageListener;
    private Map<String, Chat> mChatMaps = new HashMap<>();
    private org.jivesoftware.smack.chat.ChatManager mMultiLoginChatManager;

    public XChatManager(ImService coreService, XMPPConnection connection) {
        mService = coreService;
        mConnection = connection;
        mLoginUserId = mService.getUserId();
        mServerName = ((AppConfig) RvCache.getInstance().get(CacheEnum.IM_CONFIG)).XMPPDomain;

        initXChat();
    }

    private void initXChat() {
        mChatManager = ChatManager.getInstanceFor(mConnection);
        mChatManager.setXhmtlImEnabled(true);
        mMessageListener = new XChatMessageListener(mService);
        mChatManager.addIncomingListener(mMessageListener);

        mMultiLoginChatManager = org.jivesoftware.smack.chat.ChatManager.getInstanceFor(mConnection);
    }

    public void reset() { // 切换账号的操作
        mChatMaps.clear();
    }

    /**
     * 发送聊天的消息
     *
     * @param toUserId 要发送给的用户
     * @param oMessage 已经存到本地数据库的一条即将发送的消息
     */
    public void sendMessage(final String toUserId, final ChatMessage oMessage) {

        ThreadManager.getPool().execute(new Runnable() {
            Chat chat = getChat(toUserId);

            public void run() {
                try {
                    Message msg = new Message();
                    msg.setType(Message.Type.chat);
                    msg.setBody(oMessage.toJsonString());
                    msg.setPacketID(oMessage.getPackId());
                    msg.setFrom(oMessage.getFromUserId());
                    msg.setTo(oMessage.getToUserId());
                    DeliveryReceiptManager.addDeliveryReceiptRequest(msg);
                    // 发送消息给其他人(一条resource不拼接的消息)
                    if (!mLoginUserId.equals(toUserId)) {// 发送转发消息 || 检测消息，直接往下走
                        try {
                            Log.e("MultiTest", "发送消息给其他人");
                            chat.send(msg);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } catch (SmackException.NotConnectedException e) {
                    // 发送异常，调用消息发送状态监听，将消息发送状态改为发送失败
                    e.printStackTrace();
                }
            }
        });
    }

    private Chat getChat(String toUserId) {
        String to = toUserId + "@" + mServerName;

        Chat chat = mChatMaps.get(toUserId);
        if (chat != null) {
            return chat;
        }
        EntityBareJid mEntityBareJid = null;
        try {
            mEntityBareJid = JidCreate.entityBareFrom(to);
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }
        chat = mChatManager.chatWith(mEntityBareJid);
        return chat;
    }

    /**
     * bug：给“我的设备”发送消息，本地查看日志，消息明明已经发送出去了，但其他端就是没有收到该条消息
     * 原因：Smack 有过一次重大升级  之前发消息的Chat对象全部变为了Chat2对象，但查看源码发现Chat2对象内有一个lockedResource对象，
     * 该对象导致了toJid只能to到与自己登录时设置的Resource一致
     * 解决方法：‘发消息给“我的设备”，转发消息给其他端，通过Chat对象来发送而非Chat2对象
     */
    private org.jivesoftware.smack.chat.Chat getChatByResource(String toUserId, String resource) {
        String s = toUserId + "@" + mServerName + "/" + resource;
        EntityJid entityJid = null;
        try {
            entityJid = JidCreate.entityFrom(s);
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }
        org.jivesoftware.smack.chat.Chat chat = mMultiLoginChatManager.createChat(entityJid);
        return chat;
    }

//    // 发送上、下线，检测(type==200)，转发消息
//    private void sendForwardMessage(ChatMessage msg) {
//        if (MyApplication.IS_SEND_MSG_EVERYONE) {
//            Log.e("msg", "sendMessageToEvery");
//            // 发消息给我的设备或发送type为200的上下线消息，必须请求回执，不然不知道是哪一端收到了
//            DeliveryReceiptManager.addDeliveryReceiptRequest(msg);
//            sendMessageToEvery(msg);
//        } else {
//            sendMessageToSome(msg);
//        }
//    }

//    private void sendMessageToEvery(ChatMessage msg) {
//        Chat chat = getChat(mLoginUserId);
//        try {
//            chat.send(msg);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//        MyApplication.IS_SEND_MSG_EVERYONE = false;
//    }

//    private void sendMessageToSome(ChatMessage msg) {
//        for (String s : MyApplication.machine) {
//            if (MachineDao.getInstance().getMachineOnLineStatus(s)) {
//                Log.e("msg", "转发给" + s + "设备");
//                org.jivesoftware.smack.chat.Chat chat = getChatByResource(mLoginUserId, s);
//                try {
//                    ChatMessage message = new ChatMessage();// 需要重新创建一个Msg，如果引用之前的Msg对象，当第一个Msg或前面的Msg还未发送出去时，可能会出问题
//                    message.setType(ChatMessage.Type.chat);
//                    message.setBody(msg.getBody());
//                    message.setPacketID(msg.getPacketID());
//                    chat.sendMessage(message);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//    }
}
