package cn.muchinfo.rma.lifecycle

import android.content.Context
import androidx.lifecycle.*


/**
 * LiveData 自动绑定的kotlin拓展
 */
fun <T> LiveData<Resource<T>>.createResourceBinder(): ResourceBinderBuilder<T> {
    return ResourceBinderBuilder(this)
}

class ResourceBinderBuilder<T> internal constructor(private val liveData: LiveData<Resource<T>>) {

    private var observeForeverWhenLifecycleOwnerIsNull = false
    private var lifecycleOwner: LifecycleOwner? = null
    fun withLifecycleOwner(lifecycleOwner: Any?): ResourceBinderBuilder<T> {
        observeForeverWhenLifecycleOwnerIsNull = true
        this.lifecycleOwner = lifecycleOwner as? LifecycleOwner
        return this
    }

    private var bindJustOnce = false
    fun withBindJustOnce(bindJustOnce: Boolean = false): ResourceBinderBuilder<T> {
        this.bindJustOnce = bindJustOnce
        if (bindJustOnce) {
            observeForeverWhenLifecycleOwnerIsNull = true
        }
        return this
    }

    private var observeSuccess = true
    fun withObserveSuccess(observeSuccess: Boolean = true): ResourceBinderBuilder<T> {
        this.observeSuccess = observeSuccess
        return this
    }

    private var observeError = true
    fun withObserveError(observeError: Boolean = true): ResourceBinderBuilder<T> {
        this.observeError = observeError
        return this
    }

    private var observerNull: Boolean = false
    fun withObserverNull(observerNull: Boolean): ResourceBinderBuilder<T> {
        this.observerNull = observerNull
        return this
    }

    private var isSuccessWhenNull: Boolean = false
    fun withIsSuccessWhenNull(isSuccessWhenNull: Boolean): ResourceBinderBuilder<T> {
        this.isSuccessWhenNull = isSuccessWhenNull
        return this
    }

    private var statusData: LiveData<Resource<*>>? = null
    fun withStatusData(statusData: LiveData<*>): ResourceBinderBuilder<T> {
        try {
            @Suppress("UNCHECKED_CAST")
            this.statusData = statusData as LiveData<Resource<*>>
        } catch (e: Exception) {
        }
        return this
    }

    fun bind(block: ((T?) -> Unit)? = null) {
        val observe = object : Observer<Resource<T>> {
            override fun onChanged(t: Resource<T>?) {
                (statusData as? MutableLiveData)?.postValue(t)
                if (t.isCompleted(observerNull).and(bindJustOnce)) {
                    liveData.removeObserver(this)
                }
                if (observeSuccess.and(t?.isSuccess() ?: isSuccessWhenNull)) {
                    block?.invoke(t?.data)
                }
                if (observeError.and(t?.isError() ?: isSuccessWhenNull.not())) {
                    block?.invoke(t?.data)
                }
            }
        }
        val owner = lifecycleOwner
        if (owner == null) {
            if (observeForeverWhenLifecycleOwnerIsNull) {
                liveData.observeForever(observe)
            }
        } else {
            liveData.observe(owner, observe)
        }
    }

}


fun <T> LiveData<T>.bindOptional(context: Context, block: Observer<T>.(T?) -> Unit): Observer<T>? = bind(context as? LifecycleOwner, block)

fun <T> LiveData<T>.bind(lifecycleOwner: LifecycleOwner?, block: Observer<T>.(T?) -> Unit): Observer<T>? {
    lifecycleOwner?.let {
        val observer = object : Observer<T> {
            override fun onChanged(t: T?) {
                this.block(t)
            }
        }
        this.observe(lifecycleOwner, observer)
        return observer
    }
    return null
}


fun <T, R> LiveData<T>.map(func: (T?) -> R): LiveData<R> {
    return Transformations.map(this, func)
}

//fun <T> MediatorLiveData<T>.addSameSource(liveData: LiveData<T>, block: ((T?) -> Unit)? = null) {
//    addSource(liveData) {
//        if (isMainThread()) {
//            value = it
//        } else {
//            postValue(it)
//        }
//        block?.invoke(it)
//    }
//}
//
//fun <T> MediatorLiveData<Resource<*>>.addResource(liveData: LiveData<Resource<T>>) {
//    try {
//        addSource(liveData) { postValue(it) }
//    } catch (e: Exception) {
//        Timber.e(e)
//    }
//}
//
//fun MediatorLiveData<*>.removeAllResource() {
//    try {
//        @Suppress("UseExpressionBody")
//        ReflectUtils.reflect(this).field("mSources").get<SafeIterableMap<LiveData<*>, *>>().map {
//            it.key
//        }.forEach {
//            removeSource(it)
//        }
//    } catch (e: Exception) {
//        LogUtils.e(e)
//    }
//}
//
//fun <T> createErrorLiveData(value: T?, throwable: Throwable = DataException(DataException.PARSE_ERROR)): LiveData<Resource<T>> {
//    return MutableLiveData<Resource<T>>().apply {
//        postValue(Resource.error(throwable, value))
//    }
//}
//
//fun <T> createEmptyLiveData(emptyStr: CharSequence? = ""): LiveData<Resource<T>> {
//    return MutableLiveData<Resource<T>>().apply {
//        postValue(Resource.empty(emptyStr))
//    }
//}