package com.gh.gamecenter.common.base.fragment

import android.os.Bundle
import android.view.View
import android.view.ViewStub
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.utils.inflateOrShow

/**
 * 这是在 BaseLazyFragment 之上添加了一些通用功能的抽象类
 *
 * 怎么将一个已有的 fragment 转化为懒加载 (延迟渲染) 的 fragment 呢？
 * (继承 ListFragment 的类请改为继承 LazyListFragment)
 *
 * 0. 删掉旧的 getInflatedLayout() 的代码，现在由 getStubLayoutId() 提供 Stub 布局 （默认为 R.layout.fragment_stub，若重写请注意提供 id 为 stub 的 ViewStub）
 * 1. 重写 getRealLayoutId()，提供实际要延迟渲染的 layout Id
 * 1. 将原有在 onCreate() 的代码移动到 onFragmentFirstVisible()
 * 2. 将原有在 onViewCreated() 的代码移动到 initRealView()
 * （注意，initRealView() 在 onFragmentFirstVisible() 中被调用，如果要初始化 viewModel 等非 UI 对象请在 super.onFragmentVisible() 调用）
 * 3. 如需使用 ViewBinding ，在 onRealLayoutInflated() 的回调中初始化 ViewBinding 即可
 * 4. onResume() 的代码移动到 onFragmentResume()，onPause() 的代码移动到 onFragmentPause()
 * 5. Done!
 */
abstract class LazyFragment : BaseLazyFragment() {

    // ViewStub + ViewBinding 有莫名的 bug，语法上没问题，但编译时通不过。
    private var mViewStub: ViewStub? = null

    private var mIsRecreatedByFragmentManager = false

    override fun onCreate(savedInstanceState: Bundle?) {
        if (savedInstanceState != null) {
            mIsRecreatedByFragmentManager = true
        }
        super.onCreate(savedInstanceState)
    }

    @Deprecated(
        "使用了 LazyFragment 以后不要 override getLayoutId()，建议 override getRealLayoutId() 或者 getStubLayoutId()",
        ReplaceWith("LazyFragment.getRealLayoutId()")
    )
    override fun getLayoutId() = if (isRecreatedByFragmentManager()) {
        getRealLayoutId()
    } else {
        getStubLayoutId()
    }

    override fun initView(view: View?) {
        super.initView(view)
        if (!isRecreatedByFragmentManager()) {
            mViewStub = mCachedView.findViewById(R.id.stub)
        }
    }

    override fun onFragmentFirstVisible() {
        super.onFragmentFirstVisible()
        inflateRealView()
        initRealView()
    }

    /**
     * 真正 inflate View 的地方
     */
    protected open fun inflateRealView() {
        if (isRecreatedByFragmentManager()) {
            onRealLayoutInflated(mCachedView)
        } else {
            mViewStub?.layoutResource = getRealLayoutId()
            mViewStub?.setOnInflateListener { _, inflatedView -> onRealLayoutInflated(inflatedView) }
            mViewStub?.inflateOrShow()?.let { mCachedView = it }
        }
    }

    protected fun isRecreatedByFragmentManager() = mIsRecreatedByFragmentManager

    /**
     * 请在这个方法之后获取初始化后的各种 view
     *
     * 替换旧 fragment 实现时，等同于 onViewCreated
     */
    protected open fun initRealView() {}

    /**
     * 提供要 stub inflate 的 layout
     */
    protected abstract fun getRealLayoutId(): Int

    /**
     * 提供含有 stub 的 layout
     */
    protected open fun getStubLayoutId(): Int {
        return R.layout.fragment_stub
    }

    /**
     * 真实 layout inflate 完成的回调，可用于 viewBinding
     */
    protected open fun onRealLayoutInflated(inflatedView: View) {}

}