package com.lukouguoji.module_base.util

import com.lukouguoji.module_base.bean.SocketEventBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.db.perference.SharedPreferenceUtil
import com.lukouguoji.module_base.http.net.Api
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.HttpLogImpl
import com.lukouguoji.module_base.ktx.loge
import com.lukouguoji.module_base.ktx.logw
import com.lukouguoji.module_base.ktx.toJson
import com.lukouguoji.module_base.model.NoticeMessageDialogModel
import dev.utils.app.HandlerUtils
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okhttp3.logging.HttpLoggingInterceptor
import java.util.concurrent.TimeUnit

object WebSocketUtil {

    // 连接超时时间(S)
    private const val TIMEOUT = 30L

    // OkHttpClient对象
    private val okHttpClient: OkHttpClient

    // WebSocket对象
    private var webSocket: WebSocket? = null

    // WebSocket是否连接
    private var connectState = false

    // 重连次数
    private var retryCount = 5

    private var sendFailCount = 10

    // WebSocket监听
    private val webSocketListener = object : WebSocketListener() {
        override fun onOpen(webSocket: WebSocket, response: okhttp3.Response) {
            showLog("onOpen")
            retryCount = 3
            connectState = true
            sendHeartBeat()
        }

        override fun onMessage(webSocket: WebSocket, text: String) {
            showLog("onMessage: $text")
            if (!text.startsWith("{")) return

            // 解析消息
            val eventBean = NetApply.gson.fromJson(text, SocketEventBean::class.java)
            // 事件总线发送消息
            FlowBus.with<SocketEventBean>(ConstantEvent.SOCKET_EVENT)
                .tryEmit(eventBean)
            NoticeMessageDialogModel.show(eventBean)
            showLog("展示弹窗")
        }

        override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
            showLog("onClosed: $code, $reason")
            closeWebSocket()
        }

        override fun onFailure(webSocket: WebSocket, t: Throwable, response: okhttp3.Response?) {
            showLog("onFailure: ${t.message}")
            connectState = false
            if (retryCount > 0) {
                connect()
                retryCount--
            } else {
                closeWebSocket()
            }
        }
    }

    // 心跳Runnable
    private val heartBeatRunnable = Runnable {
        sendMsg("ping")
        sendHeartBeat()
    }

    init {
        val logInterceptor = HttpLoggingInterceptor(HttpLogImpl())
        logInterceptor.level = HttpLoggingInterceptor.Level.BODY

        okHttpClient = OkHttpClient.Builder()
            .readTimeout(TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(TIMEOUT, TimeUnit.SECONDS)
            .connectTimeout(TIMEOUT, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .addInterceptor(logInterceptor)
            .build()
    }

    /**
     * 创建WebSocket对象
     */
    private fun createWebSocket() {
        val url = Api.BASE_URL
            .replace("http://", "ws://")
            .replace("https://", "wss://")
            .plus("service/")
            .plus(SharedPreferenceUtil.getString(Constant.Share.roleId))
        showLog("连接地址：$url")
        val request = Request.Builder().url(url).build()
        webSocket = okHttpClient.newWebSocket(request, webSocketListener)
    }

    /**
     * 连接WebSocket
     */
    fun connect() {
        if (!connectState) {
            createWebSocket()
        }
    }

    /**
     * 发送心跳
     */
    private fun sendHeartBeat() {
        HandlerUtils.postRunnable(heartBeatRunnable, 5000)
    }

    /**
     * 停止心跳
     */
    fun stopHeartBeat() {
        HandlerUtils.removeRunnable(heartBeatRunnable)
    }

    /**
     * 发送消息
     */
    fun sendMsg(msg: String) {
        val isSend = webSocket?.send(msg)
        if (isSend == true && msg == "ping") return
        showLog("发送消息：$msg, 是否发送成功：$isSend")
        if (isSend == false) {
            if (sendFailCount > 0) {
                sendFailCount--
            } else {
                closeWebSocket()
            }
        }
    }

    /**
     * 关闭WebSocket
     */
    fun closeWebSocket() {
        stopHeartBeat()
        webSocket?.close(1000, "主动关闭")
        webSocket = null
        connectState = false
    }

    private fun showLog(msg: String) {
        logw("Socket工具 : $msg")
    }
}