package com.ys.bdtp.adm.mvvm.model

import kotlinx.coroutines.flow.*

/**
 * UI 数据类
 *
 * @param state : 数据状态
 * @param  data : 真实数据
 * @param   msg : 提示信息
 */
data class Data<out T>(val state: State, val data: T? = null, val msg: String = "") {
    companion object {
        fun <T> success(data: T?): Data<T> {
            return Data(State.Success, data, "")
        }

        fun <T> failure(msg: String): Data<T> {
            return Data(State.Failure, null, msg)
        }

        fun <T> loading(): Data<T> {
            return Data(State.Loading, null, "")
        }
    }
}

/**
 * 数据状态
 */
sealed interface State {
    object Success : State
    object Loading : State
    object Failure : State
}

inline fun <ResultType, RequestType> data(
    crossinline fromDb: () -> Flow<ResultType>,
    crossinline fromNt: suspend () -> RequestType,
    crossinline onSuccess: suspend (RequestType) -> Unit,
    crossinline onFailure: (Throwable) -> Unit = {},
    crossinline isFromNt: (ResultType) -> Boolean = { true }
): Flow<Data<ResultType>> = flow {
    emit(Data.loading())
    val data = fromDb().firstOrNull()
    val isNt = data == null || isFromNt(data)

    val flow = if (!isNt) {
        fromDb().map { Data.success(it) }
    } else {
        try {
            onSuccess(fromNt())
            fromDb().map { Data.success(it) }
        } catch (e: Exception) {
            onFailure(e)
            fromDb().map { Data.failure(e.message ?: "") }
        }
    }
    emitAll(flow)
}