package com.gh.gamecenter.common.utils

import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.ServiceException
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.alibaba.sdk.android.oss.internal.OSSAsyncTask
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.alibaba.sdk.android.oss.model.PutObjectResult
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.common.entity.OssEntity
import com.gh.gamecenter.common.retrofit.RetrofitManager
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers


object OssUploadUtils {
    //上传文件类型
    enum class UploadType(val value: String) {
        GAME("game"),//后缀apk
        GAME_ARCHIVE("game_archive")//游戏存档
    }

    //获取Oss配置
    private fun getOssUpdateConfig(type: UploadType): Single<OssEntity> {
        return RetrofitManager.getInstance()
            .api
            .getOssUpdateConfig(type.value)
            .subscribeOn(Schedulers.io())

    }

    //异步上传文件
    @JvmStatic
    fun uploadFile(
        path: String,
        uploadType: UploadType,
        listener: OnUploadFileListener?,
        progressCallback: OSSProgressCallback<PutObjectRequest>? = null,
        gameId: String = "",
        archiveMD5: String = "",
    ): Disposable {
        return getOssUpdateConfig(uploadType)
            .subscribeOn(Schedulers.io())
            .flatMap { mOssEntity ->
                Single.create<String> {
                    val conf = ClientConfiguration()
                    conf.connectionTimeout = 15 * 1000
                    conf.socketTimeout = 15 * 1000
                    conf.maxConcurrentRequest = 5
                    conf.maxErrorRetry = 2

                    val credentialProvider = OSSStsTokenCredentialProvider(
                        mOssEntity.accessKeyId,
                        mOssEntity.accessKeySecret,
                        mOssEntity.securityToken
                    )
                    val oss = OSSClient(HaloApp.getInstance(), mOssEntity.endPoint, credentialProvider, conf)

                    val key =
                        if (uploadType == UploadType.GAME_ARCHIVE) "${mOssEntity.key}${gameId}_${archiveMD5}.zip" else mOssEntity.key
                    // 构造上传请求
                    val put = PutObjectRequest(mOssEntity.bucket, key, path).apply {
                        if (progressCallback != null) {
                            setProgressCallback(progressCallback)
                        }
                    }

                    val task: OSSAsyncTask<*> =
                        oss.asyncPutObject(put, object : OSSCompletedCallback<PutObjectRequest?, PutObjectResult> {
                            override fun onSuccess(request: PutObjectRequest?, result: PutObjectResult) {
                                it.onSuccess(mOssEntity.domain + key)
                            }

                            override fun onFailure(
                                request: PutObjectRequest?,
                                clientExcepion: ClientException?,
                                serviceException: ServiceException?
                            ) {
                                clientExcepion?.printStackTrace()
                                serviceException?.printStackTrace()
                                if (serviceException != null) {
                                    it.onError(Throwable(message = clientExcepion?.message + "/" + serviceException.message))
                                }
                            }
                        })
                }
            }.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { url, throwable ->
                if (url.isNotEmpty()) {
                    listener?.onSuccess(url)
                    return@subscribe
                }
                if (throwable != null) {
                    listener?.onError(throwable)
                }

            }

    }

    interface OnUploadFileListener {
        fun onSuccess(url: String)
        fun onError(e: Throwable?)
    }
}