package com.gh.gamecenter.cloudarchive

import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.entity.ArchiveEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.vspace.VArchiveHelper
import com.gh.vspace.db.VArchiveEntity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.*

class MyArchiveViewModel(
    application: Application,
    private val mType: MyArchiveFragment.Type = MyArchiveFragment.Type.MY_ARCHIVE,
    val gameId: String
) : ListViewModel<ArchiveEntity, ArchiveEntity>(application) {

    companion object {
        private const val SORT_TYPE_CREATE = "time.create:-1"
        private const val SORT_TYPE_SHARE_AND_CREATE = "time.share:-1,time.create:-1"
    }

    private val mNewApi = RetrofitManager.getInstance().newApi

    val shareSuccess = MutableLiveData<Boolean>()

    init {
        if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
            syncDownloadedArchives()
        }
    }

    /**
     * 同步已下载但还没同步到接口端的存档数据
     */
    @SuppressLint("CheckResult")
    fun syncDownloadedArchives() {
        val unSyncedDownloadedArchivesIdSet = hashSetOf<String>()
        val unSyncedDownloadedArchivesList = arrayListOf<VArchiveEntity>()
        VArchiveHelper.getVArchiveEntityList().forEach {
            if (it.isLocal == VArchiveEntity.NOT_UPLOAD) {
                unSyncedDownloadedArchivesIdSet.add(it.id)
                unSyncedDownloadedArchivesList.add(it)
            }
        }
        mNewApi.syncGameArchives(gameId, unSyncedDownloadedArchivesIdSet.toRequestBody())
            .subscribeOn(Schedulers.io())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    unSyncedDownloadedArchivesList.forEach {
                        it.isLocal = VArchiveEntity.UPLOADED
                    }
                    if (unSyncedDownloadedArchivesList.isNotEmpty()) {
                        VArchiveHelper.updateArchives(unSyncedDownloadedArchivesList)
                    }
                }
            })
    }

    override fun mergeResultLiveData() {
        mResultLiveData.addSource(mListLiveData) { list ->
            list.forEach { it.gameId = gameId }

            if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
                // 优先使用本地数据（未成功同步的数据），相同 ID 的网络数据屏蔽掉，加载到的网络数据补充到列表后面
                val localIdSet = hashSetOf<String>()
                val downloadList = VArchiveHelper.getVArchiveEntityList()
                val archiveEntityList = arrayListOf<ArchiveEntity>()
                // 2024-02-23 云存档的同步设计有些缺陷，未登录状态下的同步记录会丢失，现在暂时开放本地的云存档记录，避免同步丢失的云存档不显示的问题
                // https://jira.shanqu.cc/browse/CWZS-147?focusedCommentId=58871
                for (vArchiveEntity in downloadList) {
                    if (vArchiveEntity.gameId == gameId
                        && vArchiveEntity.type == 1
                        && list.none { it.id == vArchiveEntity.id }
                    ) {
                        localIdSet.add(vArchiveEntity.id)

                        archiveEntityList.add(
                            ArchiveEntity(
                                id = vArchiveEntity.id,
                                name = vArchiveEntity.name,
                                gameId = vArchiveEntity.gameId,
                                desc = vArchiveEntity.descContent,
                                url = vArchiveEntity.url,
                                configUrl = vArchiveEntity.configUrl,
                                md5 = vArchiveEntity.md5,
                                time = ArchiveEntity.Time(create = vArchiveEntity.time),
                                gameVersion = vArchiveEntity.gameVersion
                            )
                        )
                    }
                }

                list.forEach {
                    if (!localIdSet.contains(it.id)) {
                        archiveEntityList.add(it)
                    }
                }
                if (archiveEntityList.isNotEmpty()) {
                    // 若数据不够用
                    mLoadStatusLiveData.postValue(LoadStatus.LIST_LOADED)
                }
                mResultLiveData.postValue(archiveEntityList)
            } else {
                mResultLiveData.postValue(list)
            }
        }
    }

    override fun provideDataObservable(page: Int): Observable<List<ArchiveEntity>>? = when (mType) {
        MyArchiveFragment.Type.MY_ARCHIVE -> mNewApi.getMyArchives(gameId, page, SORT_TYPE_CREATE)
        MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE -> null
        MyArchiveFragment.Type.MY_SHARE_ARCHIVE -> mNewApi.getMyShareArchives(gameId, page, SORT_TYPE_SHARE_AND_CREATE)
    }

    override fun provideDataSingle(page: Int): Single<MutableList<ArchiveEntity>>? {
        return if (mType == MyArchiveFragment.Type.MY_DOWNLOAD_ARCHIVE) {
            mNewApi.getArchivesDownloadHistories(gameId, page, 20)
        } else {
            null
        }
    }

    @SuppressLint("CheckResult")
    fun shareArchive(archiveEntity: ArchiveEntity, shareName: String, shareDesc: String) {
        val paramsMap = mapOf(
            "share_name" to shareName,
            "share_desc" to shareDesc,
            "is_shared" to true
        )
        mNewApi.patchMyArchive(gameId, archiveEntity.id, paramsMap.toRequestBody())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    shareSuccess.postValue(true)
                    Utils.toast(getApplication(), "分享成功")
                    NewFlatLogUtils.logCloudArchiveShareDialogResult("分享成功")
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    shareSuccess.postValue(false)
                    Utils.toast(getApplication(), "分享失败")
                    NewFlatLogUtils.logCloudArchiveShareDialogResult("分享失败")
                }
            })
    }

    @SuppressLint("CheckResult")
    fun cancelShareArchive(archiveEntity: ArchiveEntity) {
        val paramsMap = mapOf(
            "is_shared" to false
        )
        mNewApi.patchMyArchive(gameId, archiveEntity.id, paramsMap.toRequestBody())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    load(LoadType.REFRESH)
                    Utils.toast(getApplication(), "取消分享成功")
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    Utils.toast(getApplication(), "取消分享失败")
                }
            })
    }

    @SuppressLint("CheckResult")
    fun editMyArchive(archiveEntity: ArchiveEntity) {
        val paramsMap = mapOf(
            "name" to archiveEntity.name
        )
        mNewApi.patchMyArchive(gameId, archiveEntity.id, paramsMap.toRequestBody())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    load(LoadType.REFRESH)
                }
            })
    }

    /**
     * 删除我的存档
     */
    @SuppressLint("CheckResult")
    fun deleteArchive(archiveEntity: ArchiveEntity) {
        mNewApi.deleteMyArchive(gameId, archiveEntity.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    load(LoadType.REFRESH)
                    Utils.toast(getApplication(), "删除成功")
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    Utils.toast(getApplication(), "删除失败")
                }
            })
    }

    /**
     * 删除我下过的存档
     */
    @SuppressLint("CheckResult")
    fun deleteSyncedArchive(archiveEntity: ArchiveEntity) {
        mNewApi.deleteSyncedGameArchive(gameId, archiveEntity.id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    load(LoadType.REFRESH)
                    Utils.toast(getApplication(), "删除成功")
                }

                override fun onFailure(exception: Exception) {
                    super.onFailure(exception)
                    Utils.toast(getApplication(), "删除失败")
                }
            })
    }

    class Factory(
        val type: MyArchiveFragment.Type = MyArchiveFragment.Type.MY_ARCHIVE,
        val gameId: String
    ) : ViewModelProvider.NewInstanceFactory() {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return MyArchiveViewModel(HaloApp.getInstance().application, type, gameId) as T
        }
    }
}