package com.remax.visualnovel.extension

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.remax.visualnovel.app.AbsView
import com.remax.visualnovel.entity.response.basenew.ResponseNew
import com.remax.visualnovel.entity.response.basenew.ResultBuilder
import com.remax.visualnovel.entity.response.basenew.parseData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch

inline fun <T> launchFlow2(
    crossinline requestBlock: suspend () -> ResponseNew<T>,
    noinline startCallback: (() -> Unit)? = null,
    noinline completeCallback: (() -> Unit)? = null,
): Flow<ResponseNew<T>> {
    return flow {
        emit(requestBlock())
    }.onStart {
        startCallback?.invoke()
    }.onCompletion {
        completeCallback?.invoke()
    }.flowOn(Dispatchers.Main)
}

/**
 * 简单的请求，不返回任何实体类, 无loading和toast,数据可通过livedata/flow监听
 */
inline fun AbsView.launchWithRequest2(crossinline requestBlock: suspend () -> Unit, showLoading: Boolean = false) {
    lifecycleScope.launch {
        flow {
            emit(requestBlock())
        }.onStart {
            if (showLoading) showLoading()
        }.onCompletion {
            if (showLoading) hideLoading()
        }.collect()
    }
}

/**
 * 调用上面的，默认loading
 */
inline fun AbsView.launchWithRequestLoading2(crossinline requestBlock: suspend () -> Unit) {
    launchWithRequest(requestBlock, true)
}

/**
 * 链式调用，返回结果的处理都在一起，viewmodel中不需要创建一个livedata对象
 * 适用于不需要监听数据变化/一次性使用的场景,比如提交表单/登录
 * 屏幕旋转，Activity销毁重建，数据会消失
 *
 * 默认无toast，无loading
 */
inline fun <reified T> AbsView.launchAndCollect2(
    crossinline requestBlock: suspend () -> ResponseNew<T>,
    showLoading: Boolean = false,
    showToast: Boolean = true,
    crossinline listenerBuilder: (ResultBuilder<T>.() -> Unit) = {}
) {
    lifecycleScope.launch {
        launchFlow2(requestBlock, { if (showLoading) showLoading() }) { if (showLoading) hideLoading() }.collect { response ->
            response.parseData(listenerBuilder, showToast)
        }
    }
}

inline fun <reified T> AbsView.launchAndLoadingCollect2(
    crossinline requestBlock: suspend () -> ResponseNew<T>, showToast: Boolean = true, crossinline listenerBuilder: (ResultBuilder<T>.() -> Unit) = {}
) {
    launchAndCollect2(requestBlock, showLoading = true, showToast = showToast, listenerBuilder = listenerBuilder)
}

/**
 * 简单flow流订阅 生命周期安全
 */
inline fun <T> Flow<T?>.flowWithLaunch2(
    lifecycleOwner: LifecycleOwner, minActiveState: Lifecycle.State = Lifecycle.State.STARTED, crossinline resCallback: ((t: T?) -> Unit)
) {
    lifecycleOwner.lifecycleScope.launch {
        flowWithLifecycle(lifecycleOwner.lifecycle, minActiveState).collect {
            resCallback.invoke(it)
        }
    }
}


fun <T> Flow<T>.flowWithLifecycle2(lifecycle: Lifecycle, minActiveState: Lifecycle.State = Lifecycle.State.STARTED): Flow<T> = callbackFlow {
    lifecycle.repeatOnLifecycle(minActiveState) {
        this@flowWithLifecycle2.collect {
            send(it)
        }
    }
    close()
}

/**
 * response liveData监听
 */
inline fun <reified T> LiveData<ResponseNew<T>>.observeIn2(
    lifecycleOwner: LifecycleOwner, showToast: Boolean = true, crossinline listenerBuilder: ResultBuilder<T>.() -> Unit
) {
    this.observe(lifecycleOwner, Observer {
        it.parseData(listenerBuilder, showToast)
    })
}

/**
 * 订阅UI上展示Flow数据流
 *
 * 状态（State）用 StateFlow,粘性的 ；事件（Event）用 SharedFlow 在其 replayCache 中保留特定数量的最新值
 * MutableSharedFlow :一次性事件，不需要重放的状态变更（例如 Toast）
 * MutableStateFlow : 页面需要的状态，比如UI的刷新，多次执行没有任何问题
 * collectLastValue = true时，stateFlow也不会发送未改变的value,就和sharedFlow一样的用法
 */
inline fun <reified T> Flow<ResponseNew<T>>.collectIn2(
    lifecycleOwner: LifecycleOwner,
    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
    showToast: Boolean = true,
    crossinline listenerBuilder: ResultBuilder<T>.() -> Unit
): Job {
    return lifecycleOwner.lifecycleScope.launch {
        flowWithLifecycle2(lifecycleOwner.lifecycle, minActiveState).collect {
            it.parseData(listenerBuilder, showToast)
        }
    }
}





