package com.doverfuelingsolutions.issp.fusion

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import com.doverfuelingsolutions.issp.data.DataStore
import com.doverfuelingsolutions.issp.fusion.callback.OnFusionEvent
import com.doverfuelingsolutions.issp.utils.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPKeys
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import com.wayne.www.waynelib.fdc.FdcClient
import com.wayne.www.waynelib.fdc.OnFdcClientStateChangedListener
import com.wayne.www.waynelib.fdc.OnFdcMessageReceivedListener
import com.wayne.www.waynelib.fdc.OnFdcServiceResponseReceivedListener
import com.wayne.www.waynelib.fdc.message.FdcMessage
import com.wayne.www.waynelib.fdc.message.ServiceResponse
import com.wayne.www.waynelib.fdc.message.ServiceResponseLogOn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

object FusionManager : LifecycleObserver, OnFdcClientStateChangedListener,
    OnFdcServiceResponseReceivedListener,
    OnFdcMessageReceivedListener {

    private var stateFusion: FdcClient.FdcClientState = FdcClient.FdcClientState.Stopped

    private val coroutineIO = CoroutineScope(Dispatchers.IO)

    var onFusionEvent: OnFusionEvent? = null

    override fun onFdcClientStateChanged(sender: FdcClient?, state: FdcClient.FdcClientState?) {
        DFSLog.i("Fusion: state = ${state?.name}")
        if (sender == null || state == null) return

        stateFusion = state
        when (state) {
            FdcClient.FdcClientState.Connected -> loginFetchInfo()
            else -> {}
        }
    }

    override fun onServiceResponseReceived(sender: FdcClient?, serviceResponse: ServiceResponse?) {
        if (sender == null || serviceResponse == null) return

        DFSLog.v("onServiceResponseReceived")
    }

    override fun onFdcMessageReceived(sender: FdcClient?, fdcMessage: FdcMessage?) {
        if (sender == null || fdcMessage == null) return

        DFSLog.v("onFdcMessageReceived")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun initialize() {
        FdcClient.getDefault().addOnFdcClientStateChangedListeners(this)
        FdcClient.getDefault().addOnFdcServiceResponseReceivedListeners(this)
        FdcClient.getDefault().addOnFdcMessageReceivedListeners(this)
        FdcClient.getDefault().start(
            SPUtil.getString(SPKeys.MIDDLE_IP),
            SPUtil.getString(SPKeys.MIDDLE_PORT).toInt(),
            DataStore.sn,
            SPUtil.getString(SPKeys.MIDDLE_WORKSTATION_ID).toInt(),
            null
        )
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun close() {
        val manager = this
        coroutineIO.launch {
            logout()
            FdcClient.getDefault().removeOnFdcClientStateChangedListeners(manager)
            FdcClient.getDefault().removeOnFdcServiceResponseReceivedListeners(manager)
            FdcClient.getDefault().removeOnFdcMessageReceivedListeners(manager)
            FdcClient.getDefault().stop()
        }
    }

    // TODO 获取油站相关信息
    private fun loginFetchInfo() {
        coroutineIO.launch {
            // retry if failed
            val success = if (login()) true else {
                DFSLog.d("Fusion: retry login after logout")
                logout()
                delay(10000)
                login()
            }
            if (!success) {
                onFusionEvent?.onLogin(false)
                return@launch
            } else {
                onFusionEvent?.onLogin(true)
            }

            // TODO station info
        }
    }

    private suspend fun login() = suspendCoroutine<Boolean> {
        val port = SPUtil.getString(SPKeys.MIDDLE_PORT).toInt()
        FdcClient.getDefault().sendLogonRequestAsync(port, port, "00.07", { _, response ->
            if (response != null && response is ServiceResponseLogOn) {
                val status = response.singleFdcData.fdcStatus
                DFSLog.d("Fusion: try login response = $status")
                if (status.equals(FusionConstants.CODE_SUCCESS, true)) {
                    DFSLog.d("Fusion: login succeeded")
                    it.resume(true)
                } else {
                    DFSLog.d("Fusion: login failed")
                    it.resume(false)
                }
            }
        }, 10000)
    }

    private suspend fun logout() = suspendCoroutine<Boolean> {
        FdcClient.getDefault().sendLogOffRequestAsync({ _, response ->
            val status = response.singleFdcData.fdcStatus
            DFSLog.d("Fusion: try logout response = $status")
            if (status.equals(FusionConstants.CODE_SUCCESS, true)) {
                DFSLog.d("Fusion: logout succeeded")
                it.resume(true)
            } else {
                DFSLog.d("Fusion: logout failed")
                it.resume(false)
            }
        }, 10000)
    }
}