package com.ysnows.base.base

import android.content.Context
import android.os.Bundle
import android.util.Log
import com.socks.library.KLog
import com.trello.rxlifecycle2.components.RxFragment
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity
import com.ysnows.base.config.VConfig
import com.ysnows.base.dialog.QMUIProgressDialog
import com.ysnows.base.emptyview.callback.LoadingCallback
import com.ysnows.base.emptyview.callback.TimeoutCallback
import com.ysnows.base.emptyview.callback.ToLoginCallback
import com.ysnows.base.inter.IPResponse
import com.ysnows.base.inter.IRepository
import com.ysnows.base.net.IResponse
import com.ysnows.base.net.NetCode
import com.ysnows.base.utils.MMKVManager
import com.ysnows.base.utils.Toasts
import com.ysnows.base.utils.UiSwitch
import com.ysnows.base.utils.exception.ExceptionUtils
import com.ysnows.base.view.BView
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit

open class BRepository : IRepository {
    open var bView: BView? = null

    /**
     * 将View传递进Presenter
     *
     * @param view
     */
    override fun attachView(view: BView?) {
        this.bView = view
    }

    override fun init() {}
    override fun view(): BView? {
        return bView
    }

    fun <D, T : IResponse<D>?> lreq(observable: Observable<T>): Observable<T> {
        return req(observable, pageReq = false, loading = true)
    }

    fun <D, T : IResponse<D>?> preq(observable: Observable<T>): Observable<T> {
        return req(observable, pageReq = true, loading = false)
    }

    fun <D, T : IResponse<D>?> req(observable: Observable<T>): Observable<T> {
        return req(observable, pageReq = false, loading = false)
    }

    fun <D, T : IPResponse<D>?> cacheReq(key: String?, clazz: Class<T>, observable: Observable<T>): Observable<T> {
        return Observable.create { emitter ->
            val t = MMKVManager.instance().decodeParcelable(key, clazz)
            if (t != null) {
                emitter.onNext(t)
            } else {
                req(observable)
                        .doOnNext { res: T ->
                            if (res?.ok()!!) {
                                val result = res.data() as T
                                val encode = MMKVManager.instance().encode(key, result)
                                KLog.d(encode)
                                emitter.onNext(result)
                            }
                        }
                        .subscribe()
            }
        }
    }

    /**
     * @param observable
     * @param pageReq 是否是页面请求
     */
    fun <D, T : IResponse<D>?> req(observable: Observable<T>, pageReq: Boolean, loading: Boolean): Observable<T> {
        return Observable.create { emitter ->
            val qmuiProgressDialog = arrayOfNulls<QMUIProgressDialog>(1)

            var subscribe = observable
                    .throttleFirst(VConfig.THROTTLE_TIME.toLong(), TimeUnit.MILLISECONDS)
                    .subscribeOn(Schedulers.io())
                    .doOnSubscribe(Consumer { disposable: Disposable ->
                        if (!disposable.isDisposed) {
                            if (pageReq) {
                                bView!!.loadService!!.showCallback(LoadingCallback::class.java)
                            }
                            if (loading) {
                                qmuiProgressDialog[0] = QMUIProgressDialog()
                                qmuiProgressDialog[0]!!.show(bView!!.context())
                            }
                        }
                    } as Consumer<Disposable>)
            if (bView != null) {
                if (view() is RxAppCompatActivity) {
                    subscribe = subscribe
                            .compose((view() as RxAppCompatActivity?)!!.bindToLifecycle())
                }
                if (view() is RxFragment) {
                    subscribe = subscribe
                            .compose((view() as RxFragment?)!!.bindToLifecycle())
                }
            }
            subscribe
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(object : Observer<T> {
                        override fun onSubscribe(d: Disposable) {}
                        override fun onNext(iResponse: T) {

                            if (iResponse?.code() == NetCode.CODE_OFFLINE) {
                                if (pageReq) {
                                    bView?.loadService?.showCallback(ToLoginCallback::class.java)
                                }
                                bView?.processCodeOffline()
                                bView?.toLogin()

                            } else {
                                if (pageReq) {
                                    bView?.loadService?.showSuccess()
                                }
                            }
                            emitter.onNext(iResponse)
                        }

                        override fun onError(e: Throwable) {
                            e.printStackTrace()
                            if (pageReq) {
                                bView!!.loadService!!.showCallback(TimeoutCallback::class.java)
                            } else if (loading) {
                                qmuiProgressDialog[0]!!.dismiss()
                                view()!!.toast(ExceptionUtils.getExceptionName(e))
                            } else {
                                view()!!.toast(ExceptionUtils.getExceptionName(e))
                            }
                            if (view()!!.isNeedRefresh) {
                                view()!!.refreshing(false)
                            }
                            emitter.onError(e)
                        }

                        override fun onComplete() {
                            if (loading) {
                                qmuiProgressDialog[0]!!.dismiss()
                            }
                            if (view()!!.isNeedRefresh) {
                                view()!!.refreshing(false)
                            }
                            emitter.onComplete()
                        }
                    })
        }
    }

    val context: Context?
        get() = view()!!.context()

    override fun <T> single(clazz: Class<T>) {
        UiSwitch.single(view()!!.context(), clazz)
    }

    override fun <T> bundle(clazz: Class<T>, bundle: Bundle?) {
        UiSwitch.bundle(view()!!.context(), clazz, bundle)
    }

    override fun toast(msg: String?) {
        Toasts.toast(view()!!.context(), msg)
    }

    override fun toast(msgId: Int) {
        Toasts.toast(view()!!.context(), msgId)
    }
}
