package com.lukouguoji.module_base.ktx

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.lukouguoji.module_base.bean.BaseResultBean
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.interfaces.ILoading
import com.lukouguoji.module_base.util.ExceptionUtil
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONArray
import org.json.JSONObject

/**
 * @author：孟凡华
 * @date：2022/11/21
 * @desc：网络请求封装
 */

/**
 * 请求回调类
 */
class ResultBuilder<T> {
    /**
     * 请求成功
     */
    var onSuccess: (data: T) -> Unit = {}

    /**
     * 请求失败
     */
    var onFailed: (code: Int, message: String) -> Unit = { _, message -> showToast(message) }

    /**
     * 请求完成
     */
    var onComplete: () -> Unit = {}
}


fun Any.toRequestBody(removeEmptyOrNull: Boolean = false): RequestBody {
    var json = NetApply.gson.toJson(this)
    if (removeEmptyOrNull) {
        if (json.startsWith("{")) {
            val jsonObject = JSONObject(json)
            val keys = arrayListOf<String>()
            jsonObject.keys().forEach {
                keys.add(it)
            }
            keys.forEach {
                val value = jsonObject[it]
                if (value == null || value.toString().isEmpty()) {
                    jsonObject.remove(it)
                } else if (it == "checked" && value is JSONObject) {
                    jsonObject.remove(it)
                }
            }
            json = jsonObject.toString()
        } else if (json.startsWith("[")) {
            // TODO: 暂时只做Object,array不处理
        }
    }
    return json.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
}

private fun removeEmptyOrNullForJsonObject(jsonObject: JSONObject) {
    jsonObject.keys().forEach {
        val value = jsonObject[it]
        if (value == null || value.toString().isEmpty()) {
            jsonObject.remove(it)
        }
    }
}


/**
 * 创建异常处理器
 * 统一处理异常
 */
private fun <T> createExceptionHandler(listenerBuilder: ResultBuilder<T>.() -> Unit): CoroutineExceptionHandler {
    return CoroutineExceptionHandler { _, throwable ->
        val listener = ResultBuilder<T>().also(listenerBuilder)
        listener.onFailed(-1, ExceptionUtil.catchException(throwable))
    }
}


/**
 * 启动请求并收集数据
 */
fun <T> Any.launchCollect(
    block: suspend () -> T,
    resultBuilder: ResultBuilder<T>.() -> Unit
) {
    val scope = when (this) {
        is LifecycleOwner -> this.lifecycleScope
        is ViewModel -> viewModelScope
        else -> GlobalScope
    }
    val listener = ResultBuilder<T>().also(resultBuilder)
    flow {
        emit(block())
    }
        .flowOn(Dispatchers.IO)
        .onCompletion {
            listener.onComplete()
        }
        .onEach {
            if (it is BaseResultBean<*>) {
                if (it.verifySuccess()) {
                    listener.onSuccess(it)
                } else {
                    listener.onFailed(-1, it.msg.noNull("接口访问失败"))
                }
            } else {
                listener.onSuccess(it)
            }
        }
        .flowOn(Dispatchers.Main)
        .launchIn(scope)
}

fun <T> ILoading.launchLoadingCollect(
    block: suspend () -> T,
    resultBuilder: ResultBuilder<T>.() -> Unit
) {
    val scope = when (this) {
        is LifecycleOwner -> this.lifecycleScope
        is ViewModel -> viewModelScope
        else -> GlobalScope
    }
    val listener = ResultBuilder<T>().also(resultBuilder)
    flow {
        emit(block())
    }
        .flowOn(Dispatchers.IO)
        .onStart {
            showLoading()
        }
        .onCompletion {
            dismissLoading()
            listener.onComplete()
        }
        .onEach {
            if (it is BaseResultBean<*>) {
                if (it.verifySuccess()) {
                    listener.onSuccess(it)
                } else {
                    listener.onFailed(-1, it.msg.noNull("接口访问失败"))
                }
            } else {
                listener.onSuccess(it)
            }
        }
        .catch {
            listener.onFailed(-1, ExceptionUtil.catchException(it))
        }
        .flowOn(Dispatchers.Main)
        .launchIn(scope)
}