package com.za.service.mqtt

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.service.ServiceManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended
import org.eclipse.paho.client.mqttv3.MqttClient
import org.eclipse.paho.client.mqttv3.MqttException
import org.eclipse.paho.client.mqttv3.MqttMessage
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence

object MyMqttClient {
	private lateinit var clientId : String
	private lateinit var topic : String

	private val mqttClient : MqttClient by lazy {
		MqttClient("tcp://${MqttConfig.END_POINT}:1883", clientId, MemoryPersistence())
	}

	private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
	private val _connectionState = MutableStateFlow(false)
	private val connectionState : StateFlow<Boolean> = _connectionState

	fun initialize(deviceId : String?) {
		clientId = "${MqttConfig.GROUP_ID}@@@$deviceId"
		topic = "${MqttConfig.TOPIC_PREFIX}/$clientId"
		setupMqttCallbacks()
		connect()
		LogUtil.print("MyMqttClient ", "initialize success")
		Log.e("MyMqttClient ", "initialize success")
	}

	private fun setupMqttCallbacks() {
		mqttClient.setCallback(object : MqttCallbackExtended {
			override fun connectComplete(reconnect : Boolean, serverURI : String) {
				val status = if (reconnect) "Reconnected" else "Connected"
				LogUtil.print("MyMqttClient ", "$status to: $serverURI")
				_connectionState.value = true
				subscribeTopic()
			}

			override fun connectionLost(throwable : Throwable) {
				LogUtil.print("MyMqttClient ", "Connection lost: ${throwable.message}")
				_connectionState.value = false
			}

			override fun messageArrived(topic : String, mqttMessage : MqttMessage) {
				Handler(Looper.getMainLooper()).post {
					val message = String(mqttMessage.payload)
					LogUtil.print("MyMqttClient ", "Message arrived: $message")
					ServiceManager.handlerPushMsg(message)
				}
			}

			override fun deliveryComplete(token : IMqttDeliveryToken) {
				LogUtil.print("MyMqttClient ", "Message delivery complete")
			}
		})
	}

	private fun connect() {
		if (connectionState.value && mqttClient.isConnected) {
			LogUtil.print("MyMqttClient ", "Already connected")
			return
		}

		coroutineScope.launch {
			try {
				val options = ConnectionOptionWrapper(MqttConfig.INSTANCE_ID,
					MqttConfig.ACCESS_KEY,
					clientId,
					MqttConfig.SECRET_KEY).mqttConnectOptions

				withContext(Dispatchers.IO) {
					mqttClient.connect(options)
				}
				_connectionState.value = true // Update connection state after successful connection
			} catch (e : MqttException) {
				LogUtil.print("MyMqttClient ", "Connection failed: ${e.message}")
				_connectionState.value = false // Update connection state on failure
			}
		}
	}

	//检测mqtt连接状态
	fun publishMessage() {
		if (mqttClient.isConnected) {
			LogUtil.print("MyMqttClient ", "mqttClient.hasConnected")
			return
		}
		LogUtil.print("MyMqttClient ", "mqttClient 断开重新初始化")
		ServiceManager.initialize(GlobalData.application)
	}

	private fun subscribeTopic() {
		coroutineScope.launch {
			try {
				mqttClient.subscribe(topic, MqttConfig.QOS_LEVEL)
				LogUtil.print("MyMqttClient ", "Subscribed to topic: $topic")
			} catch (e : MqttException) {
				LogUtil.print("MyMqttClient ", "Subscribe failed: ${e.message}")
			}
		}
	}

	fun disconnect() {
		coroutineScope.launch {
			try {
				if (connectionState.value) {
					mqttClient.disconnect()
					_connectionState.value = false
					LogUtil.print("MyMqttClient ", "Disconnected successfully")
				}
			} catch (e : MqttException) {
				LogUtil.print("MyMqttClient ", "Disconnect failed: ${e.message}")
			} finally {
				coroutineScope.cancel()
			}
		}
	}
}
