package com.tcl.ah.tvcontrol.mqtt;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.util.Log;

import com.tcl.ah.tvcontrol.Constants;
import com.tcl.ah.tvcontrol.MyApplication;
import com.tcl.ah.tvcontrol.mqtt.config.MqttConfig;
import com.tcl.ah.tvcontrol.service.MyMqttService;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class MQTTHelper {


    private Context context;
    private String SERVER_URI;
    private String CLIENT_ID;
    private static volatile boolean HasClientId = false;
    private boolean isConnected = false;

    private String USER_NAME;
    private String PASSWORD;
    private String mTopic;

    private MqttAndroidClient mClient;

    private static final String TAG = "MQTTHelper";

    public static MQTTHelper INSTANCE;

    MqttCallback mqttCallback;
    MyMqttService myMqttService;
    Handler mHandler;

    ScheduledExecutorService mRetryService;
    ScheduledFuture mRetryFutureTask;

    // mHeartBeatService = Executors.newSingleThreadScheduledExecutor();

    //mHeartFuture = mHeartBeatService.scheduleWithFixedDelay(mHeartRunnable, 0, HEART_DELAY, TimeUnit.MILLISECONDS);

//    public static MQTTHelper getInstance(Context context, MqttConfig mqtt, MqttCallback mqttCallback) {
//
//
//        if (INSTANCE == null) {
//            synchronized (MQTTHelper.class) {
//                if (INSTANCE == null) {
//                    INSTANCE = new MQTTHelper(context, mqtt, mqttCallback);
//                }
//            }
//        }
//
//        return INSTANCE;
//    }

    public MQTTHelper(Context context, MqttConfig mqtt, MqttCallback mqttCallback, Handler mHandler) {

        this.context = context;
        this.mHandler = mHandler;
        this.mTopic = mqtt.getTopic();
        this.SERVER_URI = mqtt.getServerUrl();
        this.CLIENT_ID = mqtt.getClientId();
        this.USER_NAME = mqtt.getUsername();
        this.PASSWORD = mqtt.getPassword();
        this.mqttCallback = mqttCallback;
        this.myMqttService = myMqttService;
        //todo test
//        this.CLIENT_ID = "d814df5c595d_TvRemoteControl";
//        this.USER_NAME = "tcl";
//        this.PASSWORD = "tcl801";
        Log.i(TAG, "mTopic," + mTopic);
        Log.i(TAG, "SERVER_URI," + SERVER_URI);
        Log.i(TAG, "CLIENT_ID," + CLIENT_ID);
        Log.i(TAG, "USER_NAME," + USER_NAME);
        //Log.i(TAG, "PASSWORD," + PASSWORD);


        if (!HasClientId) {
            pos = new Random().nextInt(100);
            HasClientId = true;
        }
        mClient = new MqttAndroidClient(context.getApplicationContext(), SERVER_URI, pos + ":" + CLIENT_ID);
        //此设置容易出错,不需要存储持久话对象
        //        mClient = new MqttAndroidClient(context.getApplicationContext(), SERVER_URI, pos + ":" + CLIENT_ID
//                , new MemoryPersistence());


    }

    MqttConnectOptions connectOptions;

    /**
     * 触发连接
     */
    public synchronized void doConnect() {
        Log.i(TAG, "doConnect");
        connectOptions = new MqttConnectOptions();
        //强制设置3.1.1
        connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
        connectOptions.setUserName(USER_NAME);
        connectOptions.setPassword(PASSWORD.toCharArray());
        connectOptions.setAutomaticReconnect(true);
        //设置是否清除session，清除后服务器不会保留记忆
        connectOptions.setCleanSession(true);
        //设置超时时间，默认30s
        connectOptions.setConnectionTimeout(30);
        //设置心跳时间，默认60s
        connectOptions.setKeepAliveInterval(60);//[60-300]

        if (mqttCallback != null) {
            mClient.setCallback(mqttCallback);
        }

        connect(connectOptions);

    }

    private synchronized void connect(MqttConnectOptions connectOptions) {
        try {
            mClient.connect(connectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "onSuccess：");
                    try {

                        DisconnectedBufferOptions disconnectedBufferOptions =
                                new DisconnectedBufferOptions();
                        disconnectedBufferOptions.setBufferEnabled(true);
                        disconnectedBufferOptions.setBufferSize(100);
                        disconnectedBufferOptions.setPersistBuffer(false);
                        disconnectedBufferOptions.setDeleteOldestMessages(false);
                        mClient.setBufferOpts(disconnectedBufferOptions);

                        subscribeToTopic();

                        cancelRetry();

                    } catch (Exception e) {
                        Log.e(TAG, "onSuccess：" + e.toString());
                    }

                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    isConnected = false;
                    Log.e(TAG, "Throwable：" + exception.toString());
                    String errStr = exception.toString();
                    //已连接客户机 (32100) 已在进行连接 (32110)
                    if (errStr.contains("SocketTimeoutException")) {
                        retry();
                    } else if (errStr.contains("无效客户机")) {
                        //retry();
                        System.exit(0);
                        //已连接客户机 、 已在连接客户机
                    } else if (errStr.contains("32100") || errStr.contains("32110")) {
                        System.exit(0);
                    }
                }
            });
        } catch (MqttException e) {
            isConnected = false;
            Log.e(TAG, "MqttException：" + e.toString());
            e.printStackTrace();

        }
    }

    private void cancelRetry() {
        if (handler != null)
            handler.removeCallbacks(delayRunnable);
        if (mRetryFutureTask != null) {
            mRetryFutureTask.cancel(true);
            mRetryFutureTask = null;
            mRetryService = null;
        }
    }

    private static volatile int pos;

    private void retry() {
        Log.i(TAG, "this is start retry：");
        mRetryService = Executors.newSingleThreadScheduledExecutor();

        mRetryFutureTask = mRetryService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    if (mClient == null) return;
                    mClient.disconnect();
                    pos = new Random().nextInt(100);
                    mClient = new MqttAndroidClient(context.getApplicationContext(), SERVER_URI, pos + ":" + CLIENT_ID);

                    if (mqttCallback != null) {
                        mClient.setCallback(mqttCallback);
                    }

                    doConnect();

                } catch (Exception er) {
                    er.printStackTrace();
                    Log.i(TAG, "retry MqttException：" + er.toString());
                }

            }
        }, 3000, 5000, TimeUnit.MILLISECONDS);

    }

    /**
     * 判断网络是否连接
     */
    private boolean isConnectIsNormal() {
        ConnectivityManager connectivityManager = (ConnectivityManager) MyApplication.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()) {
            String name = info.getTypeName();
            Log.i(TAG, "当前网络名称：" + name);
            return true;
        } else {
            Log.i(TAG, "没有可用网络");
            /*没有可用网络的时候，延迟5秒再尝试重连*/
            delayConnect();
            return false;
        }
    }

    Handler handler = new Handler();

    private void delayConnect() {

        handler.removeCallbacks(delayRunnable);
        handler.postDelayed(delayRunnable, 5000);
    }

    Runnable delayRunnable = new Runnable() {
        @Override
        public void run() {
            connect(connectOptions);
        }
    };

    public void subscribeToTopic() {
        Log.i(TAG, "subscribeToTopic" + mTopic);
        try {
            mClient.subscribe(mTopic, 1, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    isConnected = true;
                    Log.i(TAG, "subscribeToTopic success," + asyncActionToken.getUserContext());
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "subscribeToTopic fail," + asyncActionToken.toString());
                }
            });

        } catch (MqttException ex) {
            ex.printStackTrace();
            Log.e(TAG, "subscribeToTopic:" + ex.toString());
            retry();
        }

        mHandler.removeMessages(MyMqttService.FLAG_SUBSCRIBE_TOPIC);
        mHandler.sendEmptyMessageDelayed(MyMqttService.FLAG_SUBSCRIBE_TOPIC, 30 * 1000);
    }

    public void publish(String topic, MqttMessage mqttMessage) {
        if (mClient != null && mClient.isConnected()) {
            try {
                mClient.publish(topic, mqttMessage);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    public void disconnect() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    if (mClient != null) {
                        mClient.disconnect();
                    }
                } catch (MqttException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}
