package com.qmai.zqtoolkit.base.scale

import android.content.Context
import android.util.Log
import com.blankj.utilcode.util.GsonUtils
import com.qmai.zqtoolkit.ConnectState
import com.qmai.zqtoolkit.LivingWeight
import com.qmai.zqtoolkit.ScaleInfo
import com.qmai.zqtoolkit.base.ZqScaleKit
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
import java.math.BigDecimal

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

    abstract val TAG: String
    abstract val SCALE_TYPE: QmScaleBrand
    abstract val STABLE_COUNT: Int //顶尖称有假稳定情况，设置稳定达到一定次数后再给业务发数据
    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)
        }
    }

    override fun updateWeight(weight: LivingWeight) {
        GlobalScope.launch {
            //稳定状态且读数正常
            if (weight.isStable && !weight.isReadErr) {
                readErrCache.clear()
                if (BigDecimal(weight.weight) < BigDecimal.ZERO) {
                    _livingWeight.emit(weight)
                } else {
                    when {
                        stableWeight.size == STABLE_COUNT -> {
                            var 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 {
                _livingWeight.emit(weight)
                if (weight.isReadErr)
                    when {
                        readErrCache.size >= readErrLimit -> {
                            if (readErrCache.toSet().size == 1)
                                disconnect()
                            connectCache.clear()
                        }
                        else -> readErrCache.add(true)
                    }
            }
        }
    }


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

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