package com.gamedog.vididin.core.data.repository.refreshloadmore

import com.ama.core.architecture.page.RefreshLoadMoreRepository
import com.ama.core.architecture.util.LoadState
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update
import java.util.UUID


@Suppress("KDocUnresolvedReference")
abstract class BaseMemoryRefreshLoadMoreRepository<Key : Any?, Value : Any>(private val initKey: Key) :
    RefreshLoadMoreRepository<Value> {
    private val forceUpdateFlow = MutableStateFlow("")
    private val keyFlow = MutableStateFlow(initKey)
    private var finish: (() -> Unit)? = null

    val tempListFlow = MutableStateFlow<List<Value>?>(null)

    // 加载的（包含刷新、加载）状态，控制其Ui效果。
    override val loadState = MutableStateFlow<LoadState?>(null)

    private val getDataFlow: Flow<Key?> = combine(keyFlow, forceUpdateFlow) { key, _ ->
        val isRefresh = key == initKey

        // LoadState-Loading
        loadState.update {
            LoadState.Loading(
                isRefresh = isRefresh,
                isCurrentDisplayEmptyList = tempListFlow.value.isNullOrEmpty()
            )
        }
        try {
            // currentKeyList
            val currentKeyList = getListDataByKey(key, pageSize)
            val successList = if (isRefresh) currentKeyList else {
                // 加载，结果不为空才加，否则使用原来的。
                (currentKeyList?.let { (tempListFlow.value ?: emptyList()) + it }
                    ?: tempListFlow.value)
            }
            // Result-Success
            tempListFlow.update {
                successList
            }
            // LoadState-Success
            delay(1) // 延时1毫秒，解决获取数据太快，导致loadState丢失上面设置的LoadState.Loading状态。
            loadState.update {
                LoadState.Success(
                    isRefresh = it!!.isRefresh,
                    isCurrentDisplayEmptyList = successList.isNullOrEmpty(),
                    isNoMoreData = isNoMoreData(currentKeyList),
                )
            }
            // 通知完成
            notifyFinish()

            key
        } catch (e: Exception) {
            e.printStackTrace()
            val errorList = if (isRefresh) null else tempListFlow.value
            // Result-Error
            // 思考，异常要不要在此接收处理
            // -需要，因为
            tempListFlow.update {
                errorList
            }
            // LoadState-Success
            delay(1) // 延时1毫秒，解决获取数据太快，导致loadState丢失上面设置的LoadState.Loading状态。
            loadState.update {
                LoadState.Error(
                    isRefresh = it!!.isRefresh,
                    isCurrentDisplayEmptyList = errorList.isNullOrEmpty(),
                    error = e
                )
            }
            // 通知完成
            notifyFinish()

            key
        }
    }

    override val dataListFlow: Flow<List<Value>?> = combine(getDataFlow, tempListFlow) { _, oldList ->
        // 每一次数据，都有提交，因为getDataFlow，不管成功与失败，始终有值在发出。
        oldList
    }

    override fun refresh(finish: (() -> Unit)?) {
        this.finish = finish
        forceUpdateKey(initKey)
    }

    override fun load() {
        val nextKey = getNextKey()
        forceUpdateKey(nextKey)
    }

    override fun loadRetry() {
        val currentKey = getCurrentKey()
        forceUpdateKey(currentKey)
    }

    abstract val pageSize: Int

    // 获取列表数据
    abstract suspend fun getListDataByKey(key: Key, pageSize: Int): List<Value>?

    // 获取下个Key
    abstract fun getNextKey(): Key

    // 获取当前Key
    fun getCurrentKey(): Key = keyFlow.value

    // 是否没有更多，子类可重写。
    open fun isNoMoreData(currentKeyList: List<Value>?) = (currentKeyList?.size ?: 0) < pageSize

    private fun forceUpdateKey(key: Key) {
        if (keyFlow.value == key) {
            // 相同，强制更新
            forceUpdateFlow.value = UUID.randomUUID().toString()
        } else {
            // 不同，普通更新
            keyFlow.value = key
        }
    }

    private fun notifyFinish() {
        finish?.invoke()
        finish = null
    }
}