package com.gh.gamecenter.video.upload

import android.os.Environment
import com.gh.gamecenter.common.entity.OssEntity
import com.gh.gamecenter.common.utils.NetworkUtils
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import com.volcengine.tos.TOSClientConfiguration
import com.volcengine.tos.TOSV2ClientBuilder
import com.volcengine.tos.auth.StaticCredentials
import com.volcengine.tos.model.`object`.UploadFileV2Input
import com.volcengine.tos.transport.TransportConfig
import java.io.File


/**
 * todo BUG 上传过程中遇到网络问题中断 onFailure()方法无法响应
 * https://github.com/aliyun/aliyun-oss-android-sdk/issues/75
 */
class UploadThread(
    private val mOssEntity: OssEntity,
    private val mUploadListener: OnUploadListener
) : Thread() {

    private var mProgressCallbackTimeInMills: Long = 0

    private var mLastSize: Long = 0
    private var mLastTime: Long = 0

    private var mNeedInvokeFailureInCompleted = true

    private val mMaxRetryCount = 3
    private var mRetryCount: Int = 0

    private var mUploadInput: UploadFileV2Input? = null

    override fun run() {
        super.run()

        val recordDirectory = HaloApp.getInstance().filesDir.absolutePath + "/oss_record/"
        val recordDir = File(recordDirectory)
        if (!recordDir.exists()) {
            recordDir.mkdirs()
        }

        try {
            val input = UploadFileV2Input()
                .setKey(mOssEntity.key)
                .setBucket(mOssEntity.bucket)
                .setFilePath(mOssEntity.uploadFilePath)
                .setEnableCheckpoint(true)
                .setCancelHook(true)
                .setCheckpointFile(recordDirectory)
                .setPartSize(10 * 1024 * 1024)
                .setTaskNum(1)
                .setDataTransferListener {
                    Utils.log(
                        "OssUpload",
                        "upload progress changed, type: ${it.type}, consumedBytes -> ${it.consumedBytes}, totalBytes -> ${it.totalBytes}"
                    )
                    val currentTimeInMills = System.currentTimeMillis()
                    if (currentTimeInMills - mProgressCallbackTimeInMills > 200L) {
                        // consumedBytes和totalBytes以字节为单位
                        mUploadListener.onProgressChanged(
                            mOssEntity.uploadFilePath,
                            it.consumedBytes / 1000,
                            it.totalBytes / 1000,
                            getSpeed(it.consumedBytes / 1000)
                        )
                        mProgressCallbackTimeInMills = currentTimeInMills
                    }
                }
                .apply {
                    mUploadInput = this
                }
            val config = TransportConfig.builder()
                .readTimeoutMills(5 * 1000)
                .writeTimeoutMills(5 * 1000)
                .connectTimeoutMills(5 * 1000)
                .maxRetryCount(2)
                .build()

            val configuration = TOSClientConfiguration.builder()
                .transportConfig(config)
                .region(mOssEntity.region)
                .endpoint(mOssEntity.endPoint)
                .credentials(
                    StaticCredentials(mOssEntity.accessKey, mOssEntity.secretKey)
                        .withSecurityToken(mOssEntity.securityToken)
                )
                .build()

            val tos = TOSV2ClientBuilder().build(configuration)

            tos.uploadFile(input)
            Utils.log("OssUpload", "upload succeed, path -> ${mOssEntity.uploadFilePath}")
            mRetryCount = 0
            mNeedInvokeFailureInCompleted = false
            mUploadListener.onUploadSuccess(mOssEntity.uploadFilePath, mOssEntity.domain + mOssEntity.key)
        } catch (e: Throwable) {
            Utils.log("OssUpload", "upload failed, exception -> $e")
            mNeedInvokeFailureInCompleted = false
            mUploadListener.onUploadFailure(
                mOssEntity.uploadFilePath,
                e.message ?: "$e"
            )
        }

        Utils.log(UploadThread::class.java.simpleName + "=>upload task completed::" + mNeedInvokeFailureInCompleted)
        if (mNeedInvokeFailureInCompleted) {
            if (File(mOssEntity.uploadFilePath).exists() &&
                NetworkUtils.isNetworkConnected(HaloApp.getInstance().application)
            ) {
                if (mRetryCount <= mMaxRetryCount) {
                    sleep(2000)
                    run()
                }
                mRetryCount++
            } else {
                mUploadListener.onUploadFailure(mOssEntity.uploadFilePath, "not error body")
            }
        }
    }

    // kb/s
    private fun getSpeed(currentSize: Long): Long {
        val currentTime = System.currentTimeMillis()
        Utils.log(
            "OssUpload",
            "getSpeed currentSize: $currentSize currentTime: $currentTime, lastTime: $mLastTime, lastSize: $mLastSize"
        )
        return if (currentTime != mLastTime && mLastTime != 0L) {
            val time = currentTime - mLastTime
            val size = currentSize - mLastSize
            mLastTime = currentTime
            mLastSize = currentSize
            size * 1000 / time
        } else if (mLastTime == 0L) {
            mLastTime = System.currentTimeMillis()
            mLastSize = currentSize
            0
        } else {// currentTime == mLastTime
            mLastSize * 1000 / mLastTime
        }
    }

    fun cancel() {
        mNeedInvokeFailureInCompleted = false
        mUploadInput?.cancelHook?.cancel(false)
    }
}