package com.qmai.zqtoolkit.base.scale

import android.content.Context
import com.qmai.zqtoolkit.ConnectState
import com.qmai.zqtoolkit.LivingWeight
import com.qmai.zqtoolkit.ScaleInfo
import com.qmai.zqtoolkit.config.QmScaleBrand
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch

/**
 * tongzi
 * 2022/4/29
 */
abstract class ScaleBaseKit : ScaleBaseAction, ScaleUpdateAction {

    abstract val TAG: String
    abstract val SCALE_TYPE: QmScaleBrand
    abstract val STABLE_COUNT: Int //顶尖称有假稳定情况，设置稳定达到一定次数后再给业务发数据:必须 > 0
    abstract val CONECT_CHECK_COUNT: Int //中崎外接称+sunmi 不处于物理连接状态，连接也能返回成功，增加读取重量次数，二次确认是否连接
    var lastTryScale: ScaleInfo? = null
    private var lastConnectScale: ScaleInfo? = null

    private val _connectState = MutableSharedFlow<ConnectState>()
    val connectState: SharedFlow<ConnectState> = _connectState

    private val _livingWeight = MutableSharedFlow<LivingWeight>()
    val livingWeight: SharedFlow<LivingWeight> = _livingWeight


    private val _scaleLog = MutableSharedFlow<String>()
    val scaleLog: SharedFlow<String> = _scaleLog

    private var stableWeight = mutableListOf<LivingWeight>()

    var connectCache = mutableListOf<Boolean>()

    private val readErrLimit = 10
    private var readErrCache = mutableListOf<Boolean>()

    override fun connect(
        cxt: Context?,
        scale: ScaleInfo
    ) {
        lastTryScale = scale
    }

    override fun disconnect() {
        stopReadData()
        updateState(ConnectState(false, "断开连接"))
    }

    override fun updateState(state: ConnectState) {
        //保存连接成功的配置
        lastConnectScale = if (state.isConnect) {
            lastTryScale
        } else null
        GlobalScope.launch(context = Dispatchers.IO) {
            _connectState.emit(state)
        }
    }

    override fun updateScaleInfo(info: String) {
        GlobalScope.launch(context = Dispatchers.IO) {
            _scaleLog.emit(info)
        }
    }

    private fun String?.toDoubleOrZero(): Double {
        return try {
            this?.toDouble() ?: 0.0
        } catch (e: Exception) {
            0.0
        }
    }

    private var lastLivingWeight: LivingWeight? = null

    /**
     * 判断是否需要立即发送
     */
    private fun shouldEmitOnce(weight: LivingWeight): Boolean {
        val lastNum = lastLivingWeight?.weight.toDoubleOrZero()
        val num = weight.weight.toDoubleOrZero()
        return (lastNum > 0 && num <= 0.0) || (lastNum < 0 && num >= 0)
    }

    override fun updateWeight(weight: LivingWeight) {
        GlobalScope.launch {
            //稳定状态且读数正常
            if (weight.isStable && !weight.isReadErr && !shouldEmitOnce(weight)) {
                readErrCache.clear()
                when {
                    stableWeight.size == STABLE_COUNT -> {
                        val single = stableWeight.distinctBy { it.weight }
                        if (single.size == 1) {
                            //给业务的unit要小写
                            if (weight.unit.isNotEmpty())
                                weight.unit = weight.unit.lowercase()
                            single.firstOrNull()?.let {
                                _livingWeight.emit(it)
                            }
                        }
                        stableWeight.clear()
                    }

                    stableWeight.size > STABLE_COUNT -> stableWeight.clear()
                    else -> stableWeight.add(weight)
                }
            } else {
                stableWeight.clear()
                _livingWeight.emit(weight)
                if (weight.isReadErr)
                    when {
                        readErrCache.size >= readErrLimit -> {
                            if (readErrCache.toSet().size == 1)
                                disconnect()
                            connectCache.clear()
                        }

                        else -> readErrCache.add(true)
                    }
            }
            lastLivingWeight = weight
        }
    }


    override fun getLastScale(): ScaleInfo? {
        return lastConnectScale
    }

    override fun isScaleSuccess(): Boolean {
        return lastConnectScale != null
    }
}