package com.example.base.ui

import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.view.ViewGroup
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.viewbinding.ViewBinding
import com.example.base.R
import com.example.base.dialog.LoadingDialog
import com.example.base.extensions.longToast
import com.example.base.utils.L
import com.example.base.viewmodel.BaseViewModel
import com.example.base.widget.TitleBar
import com.gyf.immersionbar.ImmersionBar
import com.tendcloud.tenddata.TCAgent
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.TimeoutCancellationException
import okio.Timeout
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.CancellationException
import java.util.concurrent.TimeoutException

abstract class BaseFragment<VB : ViewBinding, VM : BaseViewModel> : VBFragment<VB, VM>() {

    // 回收维护rx事件
    private var mCompositeDisposable: CompositeDisposable? = null

    // loading 对话框
    private var loadingDialog: LoadingDialog? = null

    // 自定义标题栏
    protected var mTitleBar: TitleBar? = null

    private var statusBarColor: Int = android.R.color.transparent

    private var navigationBarColor: Int = android.R.color.white

    private var isPrepared = false //该页面是否已经准备完毕

    private var pageStartTime = 0L //事件开始时间

    var isLazyLoaded = false //是否已经懒加载过

    override fun initView() {
        pageStartTime = System.currentTimeMillis()
        // 关联titleBar的返回事件
        mTitleBar = (binding.root as ViewGroup).children.find { it is TitleBar } as TitleBar?
        (requireActivity() as AppCompatActivity).setSupportActionBar(mTitleBar)

        setBackColor(android.R.color.black)

        ImmersionBar.setTitleBar(requireActivity(), mTitleBar)

        if (immersionBarEnabled()) {
            initImmersionBar()
        }

    }

    fun setBackColor(color: Int) {
        val upArrow = mTitleBar?.navigationIcon ?: ContextCompat.getDrawable(requireContext(), R.drawable.ic_back)
        upArrow?.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(requireContext(), color), PorterDuff.Mode.SRC_ATOP)
        (requireActivity() as AppCompatActivity).supportActionBar?.setHomeAsUpIndicator(upArrow)
    }

    fun setHomeAsUp(upArrow: Boolean) {
        (requireActivity() as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(upArrow)
    }

    private fun initImmersionBar() {
        ImmersionBar.with(this)
            .statusBarColor(statusBarColor)
            .navigationBarColor(navigationBarColor)
            .statusBarDarkFont(true)
            .navigationBarDarkIcon(true)
            .keyboardEnable(false)
            .keyboardMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
            .init()
    }

    private fun immersionBarEnabled(): Boolean {
        return true
    }

    override fun initListener() {
        // 返回上一页
        mTitleBar?.setNavigationOnClickListener {
            requireActivity().onBackPressed()
        }
    }

    /**
     * 显示用户等待框
     *
     * @param msg 提示信息
     */
    fun showDialog(msg: String = "请稍后...", cancelable: Boolean = false) {
        if (loadingDialog?.isShowing == true) {
            loadingDialog!!.setMessage(msg)
        } else {
            loadingDialog = LoadingDialog(context)
            loadingDialog!!.setMessage(msg)
            loadingDialog!!.setCancelable(cancelable)
            loadingDialog!!.setCanceledOnTouchOutside(false)
            loadingDialog!!.show()
        }
    }

    /**
     * 隐藏等待框
     */
    fun dismissDialog() {
        loadingDialog?.dismiss()
        loadingDialog = null
    }

    /**
     * 添加到回收管理
     */
    fun addDisposable(disposable: Disposable) {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = CompositeDisposable()
        }
        mCompositeDisposable?.add(disposable)
    }

    /**
     * 页面停留时间
     */
    fun pageDuration(): String {
        val duration = System.currentTimeMillis() - pageStartTime
        return if (duration < 1000) {
            "停留时间:${duration}ms"
        } else {
            "停留时间:${duration / 1000}s"
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        dismissDialog()
        //处理当前Fragment 所有的rx事件
        mCompositeDisposable?.dispose()
        mCompositeDisposable = null
    }

    override fun onResume() {
        super.onResume()
        TCAgent.onPageStart(context, this.javaClass.simpleName)
        isPrepared = true
        lazyLoad()
    }

    override fun onDestroy() {
        TCAgent.onPageEnd(context, this.javaClass.simpleName)
        super.onDestroy()
    }

    private fun lazyLoad() {
        if (isPrepared && !isLazyLoaded) {
            onLazyLoad()
            isLazyLoaded = true
        }
    }

    open fun onLazyLoad() {}

    override fun initObserve() {
        super.initObserve()
        mViewModel.exceptionLiveEvent.observe(this) {
            onError(it)
        }
        mViewModel.showDialogLiveEvent.observe(this) { bean ->
            if (bean.isShow) showDialog(bean.msg, bean.cancelable) else dismissDialog()
        }
        mViewModel.finishActivityLiveEvent.observe(this) {
            if (it == mViewModel) activity?.finish()
        }
    }

    /**
     * ViewModel层发生了错误
     */
    open fun onError(e: Throwable) {
        dismissDialog()

        val errorMsg = when (e) {
            is ConnectException -> "抱歉，网络连接失败"
            is HttpException -> "抱歉，网络连接失败"
            is UnknownHostException -> "抱歉，网络连接失败"
            is TimeoutException -> "抱歉，网络连接失败"
            is TimeoutCancellationException -> "抱歉，网络连接失败"
            is SocketTimeoutException -> "抱歉，网络连接失败"
            is CancellationException -> "抱歉，网络连接失败"
            is Timeout -> "抱歉，网络连接失败"
            else -> e.message ?: ""
        }

        L.d(e.toString())
        longToast(errorMsg)
    }
}