package com.ydl.ydlcommon.mvp.presenter

import android.app.Activity
import android.app.Application
import android.os.Bundle
import androidx.annotation.MainThread
import androidx.collection.ArrayMap
import com.ydl.ydlcommon.mvp.base.IPresenter
import com.ydl.ydlcommon.mvp.base.IView
import java.util.*

/**
 * Created by haorui on 2019-08-14.
 * Des: Presenter管理类
 *
 *      1.缓存Presenter
 *      2.移除缓存Presenter
 */
class PresenterManager private constructor() {

    companion object {

        internal val KEY_ACTIVITY_ID = "com.ydl.ydlcommon.core.MvpPresenterManagerActivityId"

        private val activityIdMap =
            ArrayMap<Activity, String>()
        private val activityScopedCacheMap =
            ArrayMap<String, ActivityPresenterCache>()

        internal val activityLifecycleCallbacks: Application.ActivityLifecycleCallbacks =
            object : Application.ActivityLifecycleCallbacks {
                override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                    if (savedInstanceState != null) {
                        val activityId = savedInstanceState.getString(KEY_ACTIVITY_ID)
                        if (activityId != null) {
                            activityIdMap[activity] = activityId
                        }
                    }
                }

                override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
                    val activityId = activityIdMap[activity]
                    if (activityId != null) {
                        outState.putString(KEY_ACTIVITY_ID, activityId)
                    }
                }

                override fun onActivityStarted(activity: Activity) {}

                override fun onActivityResumed(activity: Activity) {}

                override fun onActivityPaused(activity: Activity) {

                }

                override fun onActivityStopped(activity: Activity) {}

                override fun onActivityDestroyed(activity: Activity) {
                    if (!activity.isChangingConfigurations) {
                        val activityId = activityIdMap[activity]
                        if (activityId != null) {
                            val scopedCache = activityScopedCacheMap[activityId]
                            if (scopedCache != null) {
                                scopedCache.clear()
                                activityScopedCacheMap.remove(activityId)
                            }

                            if (activityScopedCacheMap.isEmpty) {
                                activity.application
                                    .unregisterActivityLifecycleCallbacks(this)
                            }
                        }
                    }
                    activityIdMap.remove(activity)
                }
            }


        @MainThread
        internal fun getOrCreateActivityScopedCache(
            activity: Activity
        ): ActivityPresenterCache {

            var activityId = activityIdMap[activity]
            if (activityId == null) {
                activityId = UUID.randomUUID().toString()
                activityIdMap[activity] = activityId

                if (activityIdMap.size == 1) {
                    activity.application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
                }
            }

            var activityScopedCache = activityScopedCacheMap[activityId]
            if (activityScopedCache == null) {
                activityScopedCache = ActivityPresenterCache()
                activityScopedCacheMap[activityId] = activityScopedCache
            }

            return activityScopedCache
        }


        @MainThread
        internal fun getActivityScope(activity: Activity): ActivityPresenterCache? {
            val activityId = activityIdMap[activity] ?: return null

            return activityScopedCacheMap[activityId]
        }


        fun <P> getPresenter(activity: Activity, viewId: String): P? {
            val scopedCache = getActivityScope(activity)
            return if (scopedCache == null) null else scopedCache.getPresenter<Any>(viewId) as P?
        }

        internal fun reset() {
            activityIdMap.clear()
            for (scopedCache in activityScopedCacheMap.values) {
                scopedCache.clear()
            }

            activityScopedCacheMap.clear()
        }


        fun putPresenter(
            activity: Activity, viewId: String,
            presenter: IPresenter<out IView>
        ) {

            val scopedCache = getOrCreateActivityScopedCache(activity)
            scopedCache.putPresenter(viewId, presenter)
        }


        fun remove(activity: Activity, viewId: String) {

            val activityScope = getActivityScope(activity)
            activityScope?.remove(viewId)
        }
    }
}



