package net.openmob.mobileimsdk.android.core;

import android.os.Handler;
import android.util.Log;

import com.renrenliao.im.im.ImMsgBean;
import com.renrenliao.im.utils.MDateUtils;
import com.renrenliao.im.utils.StringUtils;

import net.openmob.mobileimsdk.android.ClientCoreSDK;
import net.openmob.mobileimsdk.android.utils.MBThreadPoolExecutor;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;


public class QoS4SendDaemon {
    private static final String TAG = QoS4SendDaemon.class.getSimpleName();

    private static QoS4SendDaemon instance = null;

    public static final int CHECH_INTERVAL = 5000;

    public static final int MESSAGES_JUST$NOW_TIME = 5000;

    public static final int QOS_TRY_COUNT = 5;

    private ConcurrentHashMap<String, ImMsgBean> sentMessages = new ConcurrentHashMap<>();

    private ConcurrentHashMap<String, Long> sendMessagesTimestamp = new ConcurrentHashMap<>();

    private Handler handler = null;

    private Runnable runnable = null;

    private boolean running = false;

    private boolean _excuting = false;

    private boolean init = false;


    public static QoS4SendDaemon getInstance() {
        if (instance == null)
            synchronized (QoS4SendDaemon.class) {
                if (instance == null) {
                    instance = new QoS4SendDaemon();
                }
            }
        return instance;

    }

    private QoS4SendDaemon() {
        init();
    }

    private void init() {
        if (this.init)
            return;
        this.handler = new Handler();
        this.runnable = (() -> {
            if (!this._excuting) {
                ArrayList<ImMsgBean> lostMessages = new ArrayList<ImMsgBean>();
                MBThreadPoolExecutor.runInBackground(() -> {
                    ArrayList<ImMsgBean> ret = this.doRetryCheck(lostMessages);
                    MBThreadPoolExecutor.runOnMainThread(() -> {
                        this.onRetryCheck(ret);
                    });
                });
            }
        });
        this.init = true;
    }


    private ArrayList<ImMsgBean> doRetryCheck(ArrayList<ImMsgBean> lostMessages) {
        this._excuting = true;
        try {
            if (ClientCoreSDK.DEBUG) {
                Log.i(TAG, "【IMCORE】【QoS】=========== 消息发送质量保证线程运行中, 当前需要处理的列表长度为" + QoS4SendDaemon.this.sentMessages.size() + "...");
            }

            for (String key : this.sentMessages.keySet()) {
                ImMsgBean p = this.sentMessages.get(key);
                if (p != null) {
                    if (p.getRetryCount() >= QOS_TRY_COUNT) {
                        if (ClientCoreSDK.DEBUG) {
                            Log.i(QoS4SendDaemon.TAG, "【IMCORE】【QoS】指纹为" + p.getFp() + "的消息包重传次数已达" + p.getRetryCount() + "(最多" + QOS_TRY_COUNT + "次)上限，将判定为丢包！");
                        }
                        lostMessages.add(p.copy());
                        remove(p.getFp());
                        continue;
                    }
                    Long sendMessageTimestamp = this.sendMessagesTimestamp.get(key);
                    long delta = MDateUtils.currentTimMillis() - ((sendMessageTimestamp == null) ? 0L : sendMessageTimestamp);
                    if (delta <= MESSAGES_JUST$NOW_TIME) {
                        if (ClientCoreSDK.DEBUG) {
                            Log.i(TAG, "【IMCORE】【QoS】指纹为" + key + "的包距\"刚刚\"发出才" + delta + "ms(<=" + MESSAGES_JUST$NOW_TIME + "ms将被认定是\"刚刚\"), 本次不需要重传哦.");
                        }
                        continue;
                    }
                    (new LocalDataSender.SendCommonDataAsync(p) {
                        protected void onPostExecute(Integer code) {
                            if (code == 0) {
                                this.p.increaseRetryCount();
                                if (ClientCoreSDK.DEBUG)
                                    Log.i(QoS4SendDaemon.TAG, "【IMCORE】【QoS】指纹为" + this.p.getFp() + "的消息包已成功进行重传，此次之后重传次数已达" + this.p.getRetryCount() + "(最多" +  QOS_TRY_COUNT+ "次).");
                            } else {
                                Log.i(QoS4SendDaemon.TAG, "【IMCORE】【QoS】指纹为" + this.p.getFp() + "的消息包重传失败，它的重传次数之前已累计为" + this.p.getRetryCount() + "(最多" + QOS_TRY_COUNT + "次).");
                            }
                        }
                    }).execute(new Object[0]);
                    continue;
                }
                remove(key);
            }
        } catch (Exception e) {
            Log.i(TAG, "【IMCORE】【QoS】消息发送质量保证线程运行时发生异常," + e.getMessage(), e);
        }
        return lostMessages;
    }

    private void onRetryCheck(ArrayList<ImMsgBean> al) {
        if (al != null && al.size() > 0) {
            notifyMessageLost(al);
        }
        this._excuting = false;
        this.handler.postDelayed(this.runnable, CHECH_INTERVAL);
    }

    protected void notifyMessageLost(ArrayList<ImMsgBean> lostMessages) {
        if (ClientCoreSDK.getInstance().getImEvent() != null){
            ClientCoreSDK.getInstance().getImEvent().messagesLost(lostMessages);
        }
    }

    public void startup(boolean immediately) {
        this.stop();
        this.handler.postDelayed(this.runnable, immediately ? 0L : CHECH_INTERVAL);
        this.running = true;
    }

    public void stop() {
        this.handler.removeCallbacks(this.runnable);
        this.running = false;
    }

    public boolean isRunning() {
        return this.running;
    }

    public boolean isInit() {
        return this.init;
    }

    boolean exist(String fingerPrint) {
        return (this.sentMessages.get(fingerPrint) != null);
    }

    public void put(ImMsgBean p) {
        if (p == null) {
            Log.i(TAG, "Invalid arg p==null.");
            return;
        }
        if (StringUtils.isEmpty(p.getFp())) {
            Log.i(TAG, "Invalid arg p.getFp() is empty.");
            return;
        }

        if (this.sentMessages.get(p.getFp()) != null){
            Log.i(TAG, "【IMCORE】【QoS】指纹为" + p.getFp() + "的消息已经放入了发送质量保证队列，该消息为何会重复？（生成的指纹码重复？还是重复put？）");
        }
        this.sentMessages.put(p.getFp(), p);
        this.sendMessagesTimestamp.put(p.getFp(), MDateUtils.currentTimMillis());
    }

    public void remove(String fingerPrint) {
        this.sendMessagesTimestamp.remove(fingerPrint);
        ImMsgBean removedObj = this.sentMessages.remove(fingerPrint);
        Log.i(QoS4SendDaemon.TAG, "【IMCORE】【QoS】指纹为" + fingerPrint +
                "的消息已成功从发送质量保证队列中移除(可能是收到接收方的应答也可能是达到了重传的次数上限)，重试次数="
                + (removedObj != null ? removedObj.getRetryCount() : "none呵呵."));
    }

    public void clear() {
        this.sentMessages.clear();
        this.sendMessagesTimestamp.clear();
    }

    public int size() {
        return this.sentMessages.size();
    }


}