package com.zhimai.websocket.util

import android.annotation.SuppressLint
import android.content.Context
import android.widget.Toast
import com.google.gson.Gson
import com.zhimai.websocket.Config
import com.zhimai.websocket.listener.WebSocketSubscriberListener
import com.zhimai.websocket.listener.SocketConnectListener2
import com.zhimai.websocket.db.MessageDBManager
import com.zhimai.websocket.queue.QueueMessageService
import com.zhimai.websocket.RxWebSocket
import com.zhimai.websocket.WebSocketSubscriber
import com.zhimai.websocket.RxWebSocketUtil
import com.zhimai.websocket.listener.SocketConnectListener
import com.zhimai.websocket.listener.QueueMessageBackListener

import com.zhimai.websocket.listener.SocketMessageBackListener
import io.reactivex.annotations.NonNull
import okhttp3.WebSocket
import okio.ByteString
import org.json.JSONException
import org.json.JSONObject

import org.litepal.LitePal.initialize
import java.lang.Exception
import java.util.concurrent.TimeUnit


/**
 * Explain：IOT socket
 * Created on 2021/12/21.
 * @author zhangshenglong
 * 第一版只做socket ping，用于设备监听
 */
class MsgWebSocketIOTUtil(context_: Context) {
    private var context: Context? = null
    private var gson: Gson? = null

    init {
        context = context_
        gson = Gson()
    }

    /**
     * 入口
     *
     * @return
     */
    @SuppressLint("StaticFieldLeak")
    companion object {
        @SuppressLint("StaticFieldLeak")
        private var msgWebSocketUtil: MsgWebSocketIOTUtil? = null

        @Synchronized
        fun get(context: Context): MsgWebSocketIOTUtil {
            if (msgWebSocketUtil == null) {
                msgWebSocketUtil = MsgWebSocketIOTUtil(context)
            }
            return msgWebSocketUtil!!
        }
    }

    private val TAG = "---MsgWebSocketIOTUtil----"

    private var webSocketSubscriber: WebSocketSubscriber? = null

    private var client_id = ""

    /**
     * 店铺id
     */
    private var storeId = 0

    /**
     * 门店id
     */
    private var multiId = 0
    /**
     * 心跳ping的内容
     */
    private var pingData = "ping"

    /**
     * 心跳Ping的频率
     */
    private var pingRate = 5000 //ping 频率

    private var mWebSocket: WebSocket? = null
    private var mQueueInterval = 1000

    /**
     * socket链接状态
     */
    private var isConnected = false

    /**
     * socket地址
     */
    private var webSocketUrl = ""

    //通道
    private var socketWay = ""

    /**
     * 设备号
     * 绑定socket连接时使用，也是推送唯一标识
     */
    private var DeviceName = ""

    /**
     * 是否打印日志
     */
    private var isShowLog = true

    /**
     * 是否开启队列
     */
    private var useQueue = false

    /**
     * 禁用队列时 消息监听
     */
    private var socketMessageListener: SocketMessageBackListener? = null

    /**
     * 开启队列时 消息监听
     */
    private var queueMessageListener: QueueMessageBackListener? = null

    /**
     * socket连接监听
     */
    private var socketConnectListener: SocketConnectListener? = null
    private var mWebSocketSubscriberListener: WebSocketSubscriberListener? = null

    /**
     * 离线时间
     * 离线达到一定时间，自动重启socket
     */
    private var offLineTime = 0


    //socket2.0 涉及参数
    private var isSocket2 = false
    private var openTimingGetMessage = false
    private var getMessageInterval = 60000


//    private fun MsgWebSocketIOTUtil() {}

//    private fun MsgWebSocketIOTUtil(context: Context) {
//        this.context = context.getApplicationContext()
//        gson = Gson()
//    }

//    fun getInstance(context: Context): MsgWebSocketIOTUtil? {
//        if (msgWebSocketUtil == null) {
//            msgWebSocketUtil = MsgWebSocketIOTUtil(context)
//        }
//        return msgWebSocketUtil
//    }

    /**
     * 初始化数据库，此方法必须在 application 中调用
     */
    fun initSql() {
        initialize(context!!)
        MessageDBManager.deleteYesterdayAllHistory(context)
    }

    /**
     * 设置socket地址
     *
     * @param url
     */
    fun setUrl(url: String): MsgWebSocketIOTUtil {
        webSocketUrl = url
        if (StringUtil.isNotNull(webSocketUrl)) {
            socketWay = webSocketUrl.substring(webSocketUrl.lastIndexOf("/") + 1)
        }
        return msgWebSocketUtil!!
    }

    /**
     * 设置是否打印日志
     *
     * @param is_show
     */
    fun showLog(is_show: Boolean): MsgWebSocketIOTUtil {
        isShowLog = is_show
        Logger.LOG_ENABLE = isShowLog
        return msgWebSocketUtil!!
    }

    /**
     * 设置设备号
     *
     * @param device_name 绑定socket时使用
     */
    fun setDeviceName(device_name: String): MsgWebSocketIOTUtil {
        DeviceName = device_name
        return msgWebSocketUtil!!
    }

    /**
     * 设置 店铺 门店 id
     *
     */
    fun setStoreMultiId(store_id: Int,multi_id:Int): MsgWebSocketIOTUtil {
        storeId = store_id
        multiId = multi_id
        return msgWebSocketUtil!!
    }

    /**
     * ping频率
     * socket ping的频率
     * 默认 5000ms
     *
     * @param ping_rate
     */
    fun setPingRate(ping_rate: Int): MsgWebSocketIOTUtil {
        pingRate = ping_rate
        return msgWebSocketUtil!!
    }

    /**
     * 设置ping内容
     * 默认  "{\"type\":\"ping\",\"data\":\"\"}"
     * 如有改动可用此方法修改 ping的内容
     *
     * @param ping_data
     */
    fun setPingData(ping_data: String): MsgWebSocketIOTUtil {
        pingData = ping_data
        return msgWebSocketUtil!!
    }

    /**
     * 是否开启队列
     * 若不开启 接收到消息直接下放
     *
     * @param use_queue
     */
    fun useQueue(use_queue: Boolean): MsgWebSocketIOTUtil {
        useQueue = use_queue
        return msgWebSocketUtil!!
    }

    /**
     * socket消息回调
     * 不开启队列时，使用此消息监听
     *
     * @param socketMessageListener_
     */
    fun setSocketMessageListener(socketMessageListener_: SocketMessageBackListener?): MsgWebSocketIOTUtil {
        socketMessageListener = socketMessageListener_
        return msgWebSocketUtil!!
    }

    /**
     * queue消息回调
     * 开启队列时，使用此消息监听
     *
     * @param queueMessageListener_
     */
    fun setQueueMessageListener(queueMessageListener_: QueueMessageBackListener?): MsgWebSocketIOTUtil {
        queueMessageListener = queueMessageListener_
        return msgWebSocketUtil!!
    }

    fun setSocketConnectListener(socketConnectListener_: SocketConnectListener?): MsgWebSocketIOTUtil {
        socketConnectListener = socketConnectListener_
        return msgWebSocketUtil!!
    }

    /**
     * 是否是socket2.0
     *
     * @param is_socket_2
     * @return
     */
    fun isSocket2(is_socket_2: Boolean): MsgWebSocketIOTUtil {
        isSocket2 = is_socket_2
        return msgWebSocketUtil!!
    }

    /**
     * 是否开启 定时拉取消息
     *
     * @param is_open_timing_getmessage
     * @return
     */
    fun isopenTimingGetMessage(is_open_timing_getmessage: Boolean): MsgWebSocketIOTUtil {
        openTimingGetMessage = is_open_timing_getmessage
        return msgWebSocketUtil!!
    }

    /**
     * 设置拉取消息 间隔 时间
     *
     * @param time_interval
     * @return
     */
    fun setTimingGetMessageInterval(time_interval: Int): MsgWebSocketIOTUtil {
        getMessageInterval = time_interval
        return msgWebSocketUtil!!
    }

    /**
     * 连接socket
     * 最后调用此方法
     */
    fun initSocket() {
        if (StringUtil.isNull(webSocketUrl)) {
            Logger.e(TAG, "webSocketUrl is null")
            return
        }
        if (StringUtil.isNull(DeviceName)) {
            Logger.e(TAG, "DeviceName is null")
            return
        }
        Logger.e(TAG, "初始化socket  initSocket()")
        //是否开启日志
        RxWebSocketUtil.getInstance().setShowLog(isShowLog)

        //初始化ping定时器
        initPing()
        // ping/pong 设置：在设置config的时候，从okhttpclient中配置，设置5秒的心跳
//        OkHttpClient client = new OkHttpClient.Builder()
//                .connectTimeout(5, TimeUnit.SECONDS)
//                .readTimeout(3,TimeUnit.SECONDS)
//                .writeTimeout(3,TimeUnit.SECONDS)
//                .pingInterval(3, TimeUnit.SECONDS)
//                .build();
        val config: Config =
            Config.Builder() //                .setClient(client)   //if you want to set your okhttpClient
                .setShowLog(isShowLog, TAG)
                .setReconnectInterval(2, TimeUnit.SECONDS) //set reconnect interval
                //                .setSSLSocketFactory(yourSSlSocketFactory, yourX509TrustManager) // wss support
                .build()
        RxWebSocket.setConfig(config)
        Logger.e(TAG, "开启长连接；；$webSocketUrl")
        //        RxWebSocket.get(MyApplication.WEBSOCKET_HOST_AND_PORT)
        webSocketSubscriber = object : WebSocketSubscriber() {
            override fun onOpen(webSocket: WebSocket) {
                Logger.e(TAG, "onOpen1:")
                if (mWebSocketSubscriberListener != null) {
                    mWebSocketSubscriberListener!!.onOpen(webSocket)
                }
                mWebSocket = webSocket
                isConnected = true
                socketConnectListener?.connected() ?: Logger.e(TAG, "socketConnectListener==null")

            }

            override fun onMessage(@NonNull text: String) {
                Logger.e(TAG, "onMessage;;$text")
                mWebSocketSubscriberListener?.onMessage(text)
                checkMessage(text)
            }

            override fun onMessage(@NonNull bytes: ByteString) {
                mWebSocketSubscriberListener?.onMessage(bytes)
                Logger.e(TAG, bytes.toString())
            }

            override fun onReconnect() {
                Logger.e(TAG, "重连")
                if (mWebSocketSubscriberListener != null) {
                    mWebSocketSubscriberListener!!.onReconnect()
                }
                isConnected = false
                socketConnectListener?.disconnect() ?: Logger.e(TAG, "socketConnectListener==null")

            }

            override fun onClose() {
                mWebSocketSubscriberListener?.onClose() ?: Logger.e(TAG, "关闭")
                socketConnectListener?.closed() ?: Logger.e(TAG, "socketConnectListener==null")

            }

            override fun onError(e: Throwable) {
                mWebSocketSubscriberListener?.onError(e) ?: Logger.e(TAG, "错误：" + e.message)
            }
        }
        RxWebSocket.get(webSocketUrl) //        RxWebSocket.get("ws://qmapp.dev.zmcms.cn:8282")
            //RxLifecycle : https://github.com/dhhAndroid/RxLifecycle
            //                .compose(RxLifecycle.with(MyApplication.mContext).<WebSocketInfo>bindToLifecycle())//如果需要跟activity生命绑定，防止内存泄漏，可以用这个方法
            .subscribe(webSocketSubscriber!!)

        //如果开启队列，则启动队列消息服务
        if (useQueue) {
            QueueMessageService.getInstance().setInterval(mQueueInterval)
            QueueMessageService.getInstance().startPrintService { message ->
                if (queueMessageListener != null) {
                    queueMessageListener!!.reciever(message)
                } else {
                    Logger.e(TAG, "queueMessageListener==null")
                }
            }
        }
    }

    /**
     * 处理分发接收到的消息
     * 根据接收的消息，进行相应的处理，这里随便写的，要根据自己定的规则进行处理
     */
    private fun checkMessage(message: String) {
        try {
            Logger.e(TAG, "checkMessage: message= $message")
//            val jsonObject = JSONObject(message)
//            val type: String = jsonObject.optString("type")
            when (message) {
                "ping" -> {
                    sendMessage("pong")
                }

            }
        } catch (e: JSONException) {
        }
    }

    /**
     * 通知服务端 消息收到成功
     *
     * @param tag
     * @return
     */
    private fun getConfirmMessage(tag: String): String {
        return "{\"type\": \"msg-confirm\",\"data\":{\"tag\":\"$tag\"}}"
    }

    /**
     * 发送绑定/验证 请求
     */
    private fun sendBind() {
        try {
            Logger.e(TAG, "sendBind()被调用")
            val bindJson = JSONObject()
            bindJson.put("version", "1.0")
            bindJson.put("deviceId", DeviceName)
            bindJson.put("tags", "[qmzs-${storeId}_${multiId}]")
            bindJson.put("toSystem", "socket-center-message")
            bindJson.put("type", 1000)
            if (mWebSocket != null) {
                Logger.e(TAG, "发送绑定数据：" + bindJson.toString())
                mWebSocket?.send(bindJson.toString())
            }
        } catch (e: Exception) {
            Logger.e(TAG, "sendBind 错误:" + e.message)
        }
    }

    /**
     * 发送消息方法
     *
     * @param message
     * @return
     */
    fun sendMessage(message: String): Boolean {
        if (!isConnected) {
            Logger.e(TAG, "socket已断开$message")
            return false
        }
        Logger.e(TAG, "sendMessage()被调用")
        return if (mWebSocket != null) {
            Logger.e(TAG, "发送数据：$message")
            mWebSocket?.send(message)
            true
        } else {
            Logger.e(TAG, "mWebSocket==null")
            false
        }
    }

    /**
     * 获取socket连接状态
     * true:已连接
     * false:连接断开 或 未初始化
     *
     * @return
     */
    fun getConnectStatus(): Boolean {
        return isConnected
    }

    /**
     * 开始定时发送心跳
     * 这个是监测 连接是否正常的规则，可自定义
     */
    private fun initPing() {
        RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.IOT_SOCKET_PING)
        RxTimerUtil.interval(
            SysCode.RX_TIMER_TYPE.IOT_SOCKET_PING, pingRate.toLong()
        ) { number ->
            if (isConnected) {
                if (mWebSocket != null) {
                    val isPing: Boolean = mWebSocket?.send(pingData) ?: false
                    if (socketConnectListener != null && socketConnectListener is SocketConnectListener2) {
                        (socketConnectListener as SocketConnectListener2).ping(isPing)
                    }
                    if (isPing) {
                        offLineTime = 0
                    } else {
                        offLineTime++
                    }
                    Logger.e(
                        TAG,
                        if (isPing) "ping... 内容：$pingData" else "ping失败..."
                    )
                }
            } else {
                offLineTime++
                Logger.e(TAG, "Socket中断，停止ping...offLineTime$offLineTime")
            }
            if (offLineTime > 10) { //超过10次ping（50S）失败/离线50S  重启socket
                destroySocket()
                initSocket()
            }
            if (context != null) {
                if (NetWorkUtils.isOffline(context)) {
                    Toast.makeText(context, "请检查当前网络", Toast.LENGTH_SHORT).show()
                }
            }

//            //在ping里面触发 定时消息请求
//            if (isSocket2 && openTimingGetMessage) {
//                if (number * pingRate % getMessageInterval == 0L) {
//                    //定时拉取服务端打印消息
//                    getSocketServiceMessage()
//                } else {
//                    Logger.e(
//                        TAG,
//                        "number = $number  ;; pingRate = $pingRate  ;; getMessageInterval = $getMessageInterval"
//                    )
//                }
//            } else {
//                Logger.e(
//                    TAG,
//                    "isSocket2 = $isSocket2  ;; openTimingGetMessage = $openTimingGetMessage"
//                )
//            }
        }
    }

    fun destroySocket() {
        if (webSocketSubscriber != null) {
            webSocketSubscriber!!.dispose()
            Logger.e(TAG, "socket服务已关闭...")
        }
        RxTimerUtil.cancel(SysCode.RX_TIMER_TYPE.IOT_SOCKET_PING)
        Logger.e(TAG, "socket心跳已关闭...")
    }

    fun setWebSocketSubscriberListener(mWebSocketSubscriberListener: WebSocketSubscriberListener?): MsgWebSocketIOTUtil? {
        this.mWebSocketSubscriberListener = mWebSocketSubscriberListener
        return this
    }

    fun setQueueInterval(mQueueInterval: Int): MsgWebSocketIOTUtil? {
        this.mQueueInterval = mQueueInterval
        return this
    }

}