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

import com.ys.bdtp.adm.mvvm.model.nt.*
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(fail: Fail): Data<T> {
            return Data(State.Failure, null, fail.toString())
        }

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

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

/**
 * 数据请求框架
 */
fun <ResultType, RequestType> data(
    fromDb: () -> Flow<ResultType>,
    fromNt: suspend () -> Model<RequestType>,
    needNt: (ResultType) -> Boolean = { true },
    failure: (Fail) -> Unit = {},
    success: suspend (RequestType) -> Unit,
): Flow<Data<ResultType>> = flow {
    emit(Data.loading())
    val data = fromDb().firstOrNull()
    val isNt = data == null || needNt(data)

    val flow = if (!isNt) {
        fromDb().map { Data.success(it) }
    } else {
        when (val response = request(fromNt)) {
            is SuccessResponse -> {
                success(response.data)
                fromDb().map { Data.success(it) }
            }
            is FailureResponse -> {
                failure(response.fail)
                fromDb().map { Data.failure(response.fail) }
            }
        }
    }
    emitAll(flow)
}

/**
 * Flow<T> 转换为带状态 Flow<Data<T>>
 */
fun <T> Flow<T>.toStateFlow(): Flow<Data<T>> = flow {
    emit(Data.loading())
    emitAll(this@toStateFlow.map { Data.success(it) })
}
