package com.gh.gamecenter.common.syncpage

import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.annotation.SyncIgnore
import com.gh.gamecenter.common.annotation.SyncPage
import com.gh.gamecenter.common.utils.debugOnly
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.lightgame.utils.Utils
import java.lang.reflect.Field

/**
 * 页面之间实现数据同步(主要是单个字段的同步)
 *
 * 实现思路：
 * 1.把需要同步的数据以一个特殊ID作为唯一标识，并存于一个全局的仓库
 * 2.利用LiveData进行页面回调,再通过[ISyncAdapterHandler.getSyncData]找到需要被同步的数据
 * 3.最后利用反射进行数据替换,具体请见[SyncPageRepository.replaceSyncData]
 *
 * 具体的接入方式(以列表为例)：
 * 1.通过[SyncPageRepository.postSyncData]提交同步数据
 * 2.在Fragment重写[BaseFragment.addSyncPageObserver]开启同步事件监听
 * 3.在Fragment重写[BaseFragment.provideSyncAdapter]提供获取数据的来源
 *   - [BaseFragment.provideSyncAdapter]提供的Adapter必须实现[ISyncAdapterHandler]接口
 *
 */
object SyncPageRepository {

    // 只有在新增操作时，才需要进行页面刷新
    val syncPageLiveData = MutableLiveData<List<SyncDataEntity>>()

    val syncDataList = ArrayList<SyncDataEntity>()

    // size: 防止删除刚刚添加的数据
    @JvmStatic
    fun clearSyncData() {
        tryCatchInRelease {
            synchronized(syncDataList) {
                if (syncDataList.size > 0) {
                    debugOnly {
                        Utils.log("SyncPageRepository clearSyncData 存在" + syncDataList.size + "条数据尚未处理，即将删除")
                    }
                    syncDataList.clear()
                }
            }
        }
    }

    @JvmStatic
    fun removeSyncData(list: List<SyncDataEntity>) {
        tryCatchInRelease {
            synchronized(syncDataList) {
                for (syncDataEntity in list) {
                    val remove = syncDataList.remove(syncDataEntity)
                    debugOnly {
                        Utils.log(
                            "SyncPageRepository removeSyncData ->" + syncDataEntity.syncId +
                                    ", fieldName->" + syncDataEntity.syncFieldName +
                                    ", remove->" + remove
                        )
                    }
                }
            }
        }

        debugOnly {
            Utils.log("SyncPageRepository removeSyncData ->" + syncDataList.size)
        }
    }

    // 提交同步数据
    fun postSyncData(entity: SyncDataEntity) {
        tryCatchInRelease {
            synchronized(syncDataList) {
                // 检查是否存在重复操作
                for (syncDataEntity in syncDataList) {
                    if (syncDataEntity.syncId == entity.syncId && syncDataEntity.syncFieldName == entity.syncFieldName) {
                        syncDataList.remove(syncDataEntity)

                        debugOnly {
                            Utils.log("SyncPageRepository postSyncData 存在重复操作->" + entity.toJson())
                        }
                        break
                    }
                }

                syncDataList.add(entity)
                syncPageLiveData.postValue(syncDataList)

                debugOnly {
                    Utils.log("SyncPageRepository postSyncData->" + entity.toJson())
                }
            }
        }
    }

    fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean {
        val fields = if (syncData.checkInherited) {
            getAllFieldsList(rawData::class.java)
        } else rawData::class.java.declaredFields.toList()

        var isNeedNotify = false
        for (field in fields) {
            isNeedNotify = replaceSyncData(field, rawData, syncData)
            if (isNeedNotify) break
        }

        if (!isNeedNotify) {
            debugOnly {
                Utils.log("SyncPageRepository sync failure-> " + syncData.syncFieldName)
            }
        }

        return isNeedNotify
    }

    private fun replaceSyncData(field: Field, extractObject: Any, syncData: SyncDataEntity): Boolean {
        field.getAnnotation(SyncPage::class.java)?.syncNames?.forEach { syncName ->
            if (syncName == syncData.syncFieldName && field.getAnnotation(SyncIgnore::class.java) == null) {
                field.isAccessible = true
                debugOnly {
                    Utils.log(
                        "SyncPageRepository sync success-> " + syncData.syncFieldName + ", fieldName->" + field.name + ", fieldValue->" + field.get(
                            extractObject
                        )
                    )
                }
                field.set(extractObject, syncData.syncFieldValue)
                return true
            }
        }

        if (syncData.checkFieldEntity) {
            // 递归查询
            val pkgName = field.type.getPackage()?.name ?: return false
            if (pkgName.contains(HaloApp.getInstance().packageName) && field.getAnnotation(SyncIgnore::class.java) == null) {
                field.isAccessible = true
                val extractEntityObject = field.get(extractObject) ?: return false
                field.type.declaredFields.forEach {
                    if (replaceSyncData(it, extractEntityObject, syncData)) return true
                }
            }
        }
        return false
    }

    // 包括父类 Field 对象
    private fun getAllFieldsList(cls: Class<*>?): List<Field> {
        if (cls == null) return arrayListOf()
        val allFields = arrayListOf<Field>()
        var currentClass = cls
        while (currentClass != null) {
            val declaredFields = currentClass.declaredFields
            allFields.addAll(declaredFields)
            currentClass = currentClass.superclass
        }
        return allFields
    }
}