package com.xty.common.services

import android.app.*
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.IBinder
import com.alibaba.android.arouter.facade.annotation.Route
import com.xty.common.Const
import com.xty.common.LogUtils
import com.xty.common.arouter.ARouterUrl
import com.xty.common.event.MqTTEvent
import com.xty.common.event.MqttReceive
import com.xty.network.model.MqTTBean
import kotlinx.coroutines.*
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode


/**
 * mqtt服务
 */

@Route(path = ARouterUrl.MQTT_SERVICE)
class MqTTService : Service(), MqttCallback, OrderProiver {

    private var client: MqttAndroidClient? = null
    private var conOpt: MqttConnectOptions? = null

    private var host = "" //服务器地址
    private var userName = ""//账号
    private var passWord = "" //密码
    private var myTopic = "" //频道名
    private var clientId = "" //客户端ID
    private val MAX_CONNECT = 3

    private val qos = 1 //

    private var connectNum = Const.MQTT_CONNECT//断开连接 重联次数
    private var connectIntervalTime = 1 * 1000 * 60L //连接时间间隔 1分钟
    var mapScope = MainScope()
    var sleepJob: Job? = null // 睡眠工作
    var isClose=false


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
            EventBus.getDefault().post(this)
        }
        intent?.let {
            if (it.hasExtra("close")) {
                isClose=true
                closeMqtt()
            } else if (it.hasExtra("bean")) {
                isClose=false
                setClientInfo()
                var bean = it.getSerializableExtra("bean") as MqTTBean
                LogUtils.d("MQTT Info:${bean}")
                host = bean.host //服务器地址
                userName = bean.userName
                passWord = bean.password
                myTopic = "SN_MSG/${bean.appUserId}"//服务器地址
                clientId = bean.appUserId
                if (client == null) {
                    init()
                } else {
                    if (client!!.isConnected) { // 已连接
                    } else {
                        if (connectNum < Const.MQTT_CONNECT) {
                            LogUtils.d("正在重连中")
                        } else {
                            doClientConnection()
                        }
                    }
                }
            }else{
                isClose=false
                closeMqtt()
            }
        }
        return super.onStartCommand(intent, flags, startId)

    }

    /**
     * 设置连接信息
     */
    private fun setClientInfo() :Boolean{
        if (userName.isNullOrEmpty()) {
            return false
        }
        if (sleepJob != null && sleepJob!!.isActive) {
            LogUtils.d("正在等待重连中，请稍后")
            return false
        }
        val uri = host
        if(client==null){
            client = MqttAndroidClient(this, uri, clientId)
        }

        // 设置MQTT监听并且接受消息

        client!!.setCallback(this)

        conOpt = MqttConnectOptions()
        // 清除缓存
        conOpt!!.isCleanSession = true
        // 设置超时时间，单位：秒
        conOpt!!.connectionTimeout = 10
        // 心跳包发送间隔，单位：秒
        conOpt!!.keepAliveInterval = 20
        // 用户名
        conOpt!!.userName = userName
        // 密码
        conOpt!!.password = passWord.toCharArray()
        // last will message

        // last will message
        var doConnect = true
        val message = "{\"terminal_uid\":\"$clientId\"}"
        val topic = myTopic
        val retained = true
        if (message != "" || topic != "") {
            // 最后
            try {
                conOpt!!.setWill(topic, message.toByteArray(), qos, false)
            } catch (e: Exception) {
                LogUtils.e("Exception Occured message:${e.message} cause:${e.cause}")
                doConnect = false
                mqttListener.onFailure(null, e)
            }
        }

        return  doConnect

    }

    //初始化连接
    private fun init() {

        if (setClientInfo()) {
            doClientConnection()
        }
    }

    /** 连接MQTT服务器  */
    private fun doClientConnection() {
        if (!client!!.isConnected && isConnectIsNomarl()) {
            try {
                --connectNum
             /*
                MainScope().launch {
                    withContext(Dispatchers.IO){
                        val connect = client!!.connect(conOpt, null, mqttListener)
                        connect.waitForCompletion()
                    }
                }
*/

                if(!isClose){
                    client!!.connect(conOpt, null, mqttListener)
                }
            } catch (e: MqttException) {
                LogUtils.e("connect fail message:${e.message}, cause:${e.cause}")
                e.printStackTrace()
            }
        }
    }

    //将消息发布到服务器
    private fun publish(msg: String) {
        try {
            client?.let {
                if (it.isConnected) {
                    it.publish(myTopic, msg.toByteArray(), qos, false);
                }
            }
        } catch (e: MqttException) {
            LogUtils.e("connect fail message:${e.message}, cause:${e.cause}")
            e.printStackTrace();
        }
    }

    private var mqttListener = object : IMqttActionListener {
        override fun onSuccess(asyncActionToken: IMqttToken?) {
            connectNum = Const.MQTT_CONNECT //重置连接次数
            if(!myTopic.isNullOrEmpty()){
                client!!.subscribe(myTopic, 1);
            }
            LogUtils.d("连接成功")
            connectNum = MAX_CONNECT
        }

        override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
            //重联
            if (connectNum > 0) {
                doClientConnection()
                LogUtils.d("连接失败，重新连接")
            } else {
                connectNum = Const.MQTT_CONNECT
                LogUtils.d("达到最大连接次数，一分钟后重联")
                sleepConnect()
            }
        }
    }

    /**
     * 睡眠一分钟继续发起连接
     */
    private fun sleepConnect() {
        sleepJob = mapScope.launch {
            delay(connectIntervalTime) //睡眠时长
            sleepJob!!.cancel() //休眠结束 取消工作
            doClientConnection()
        }

    }


    private fun closeMqtt() {

        if (sleepJob != null) {
            sleepJob!!.cancel()
        }
        client?.let {
            it.unregisterResources()
            if (it.isConnected) {
                LogUtils.d("断开连接")
                it.disconnect()  //断开连接
            }
        }
    }

    /** 判断网络是否连接  */
    private fun isConnectIsNomarl(): Boolean {
        val connectivityManager: ConnectivityManager =
            this.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val info: NetworkInfo? = connectivityManager.activeNetworkInfo
        return if (info != null && info.isAvailable) {
            val name: String = info.typeName
            // Log.i("mtqq", "MQTT当前网络名称：$name")
            true
        } else {
            //Log.i("mtqq", "MQTT 没有可用网络")
            false
        }
    }

    override fun onDestroy() {
        client?.let {
            it.unregisterResources()
        }
        isClose=true
        LogUtils.d("服务终止mqtt ")
        try {
            closeMqtt()
            mapScope.cancel()
            userName = ""
        } catch (e: MqttException) {
            e.printStackTrace()
        }
        EventBus.getDefault().unregister(MqTTEvent(""))
        super.onDestroy()
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun connectionLost(cause: Throwable?) {

    }

    override fun messageArrived(topic: String?, message: MqttMessage?) {
        message?.let {
            var str = String(it.payload,Charsets.UTF_8)
            LogUtils.d("mqtt 接收消息:${str}")
            LogUtils.d("${Thread.currentThread()}")
            EventBus.getDefault().post(MqttReceive(str))
        }
    }

    override fun deliveryComplete(token: IMqttDeliveryToken?) {

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun publish(eventBus: MqTTEvent) {
        publish(eventBus.msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun eventAny(eventBus: Any) {
    }


    override fun init(context: Context?) {

    }
}

