package com.adealink.weparty.viewmodel

import androidx.annotation.MainThread
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelLazy
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.ViewModelStoreOwner
import com.adealink.frame.mvvm.view.ViewComponent
import com.adealink.frame.mvvm.viewmodel.createViewModelLazy


@MainThread
inline fun <reified VM : ViewModel, reified T : Fragment> ViewComponent.parentFragmentViewModels(
    parentClass: Class<T>,
    noinline ownerProducer: () -> ViewModelStoreOwner = { fragment?.findParentFragmentBy(parentClass) ?: activity!! },
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    return createViewModelLazy(
        VM::class,
        { ownerProducer().viewModelStore },
        factoryProducer
    )
}

@MainThread
inline fun <reified VM : ViewModel, reified T : Fragment> Fragment.parentFragmentViewModels(
    parentClass: Class<T>,
    noinline ownerProducer: () -> ViewModelStoreOwner = { findParentFragmentBy(parentClass) ?: activity!! },
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        val application = activity?.application ?: throw IllegalStateException(
            "ViewModel can be accessed only when Fragment is attached"
        )
        ViewModelProvider.AndroidViewModelFactory.getInstance(application)
    }
    return ViewModelLazy(VM::class, { ownerProducer().viewModelStore }, factoryPromise)
}


fun <T : Fragment> Fragment.findParentFragmentBy(parentClass: Class<T>): Fragment? {
    if (isAdded && !isDetached && context != null) {
        val parent = parentFragment
        if (parent == null) {
            return null
        }
        if (parent.javaClass === parentClass) {
            return parent
        }
        return parent.findParentFragmentBy(parentClass)
    }
    return null
}
