package com.example.base.ui

import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.base.utils.Utils
import com.example.base.viewmodel.BaseViewModel
import com.example.base.viewmodel.ViewModelScope
import com.example.base.viewmodel.ViewModelScopeType
import java.lang.reflect.ParameterizedType

abstract class VMFragment<VM : BaseViewModel> : Fragment() {

    private var _viewModel: VM? = null
    val mViewModel get() = _viewModel!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        _viewModel = initVM()

        initObserve()
    }

    /**
     * ViewModel viewModel存储位置
     * @see ViewModelScope
     */
    private fun <VM : ViewModel> Fragment.initVM(): VM {
        // 获取泛型的真实class
        val types = javaClass.genericSuperclass as ParameterizedType

        val type = types.actualTypeArguments.find {
            val clazz = it as Class<*>
            ViewModel::class.java.isAssignableFrom(clazz)
        } ?: throw RuntimeException("子页面没有传入ViewModel的泛型")

        @Suppress("UNCHECKED_CAST")
        val tClass = type as Class<VM>
        val viewModelScope = tClass.getAnnotation(ViewModelScope::class.java)
//        toast("${viewModelScope?.scope}")
        return when (viewModelScope?.scope) {
            com.example.base.viewmodel.ViewModelScopeType.ACTIVITY -> {
                // 关联到activity(可实现activity下的多个fragment数据共享)
                ViewModelProvider(requireActivity()).get(tClass)
            }
            com.example.base.viewmodel.ViewModelScopeType.GLOBAL -> {
                // 关联到 Application (可实现全局数据共享)
                ViewModelProvider(Utils.getApp()).get(tClass)
            }
            else -> {
                // 关联到fragment
                ViewModelProvider(this).get(tClass)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _viewModel = null
    }

    // init livedata监听
    open fun initObserve(){}
}
