package com.yidian.shenghuoquan.newscontent.utils

import android.content.Context
import android.util.Log
import com.google.gson.Gson
import com.ksyun.ks3.exception.Ks3Error
import com.ksyun.ks3.model.acl.CannedAccessControlList
import com.ksyun.ks3.services.AuthListener
import com.ksyun.ks3.services.Ks3Client
import com.ksyun.ks3.services.Ks3ClientConfiguration
import com.ksyun.ks3.services.handler.PutObjectACLResponseHandler
import com.ksyun.ks3.services.handler.PutObjectResponseHandler
import com.ksyun.ks3.services.request.PutObjectRequest
import com.yidian.bcommon.YdBaseApplication
import com.yidian.shenghuoquan.newscontent.http.ApiService
import com.yidian.shenghuoquan.newscontent.http.httpbean.GetKSYunObjectIdBean
import com.yidian.shenghuoquan.newscontent.http.httpbean.IGetKSYunObjectIdCallback
import com.yidian.utils.MD5Util
import com.yidian.yac.ftdevicefinger.core.FtDeviceFingerManager
import cz.msebera.android.httpclient.Header
import java.io.File

/**
 * author: yinjiacheng
 * date: 5/20/21 11:08 AM
 * description: 金山云存储
 */
class KS3Core private constructor(val context: Context) : AuthListener {

    private val client by lazy { Ks3Client(this, context) }
    private val gson by lazy { Gson() }
    private val putObjectResponseHandler by lazy {
        object : PutObjectResponseHandler() {
            override fun onTaskProgress(progress: Double) {
                // work thread
            }

            override fun onTaskFailure(
                statesCode: Int,
                error: Ks3Error?,
                responceHeaders: Array<out Header>?,
                response: String?,
                throwable: Throwable?
            ) {
                Log.e(
                    TAG,
                    "put object fail:, errorMsg: ${error?.errorMessage}"
                )
            }

            override fun onTaskSuccess(statesCode: Int, responceHeaders: Array<out Header>?) {
                Log.d(TAG, "put object success.")
            }

            override fun onTaskStart() {

            }

            override fun onTaskFinish() {

            }

            override fun onTaskCancel() {

            }
        }
    }

    private val putObjectACLResponseHandler by lazy {
        object : PutObjectACLResponseHandler() {
            override fun onSuccess(statesCode: Int, responceHeaders: Array<out Header>?) {
                Log.d(TAG, "put object acl success.")
            }

            override fun onFailure(
                statesCode: Int,
                error: Ks3Error?,
                responceHeaders: Array<out Header>?,
                response: String?,
                throwable: Throwable?
            ) {
                Log.e(TAG, "put object acl fail:, errorMsg: ${error?.errorMessage}")
            }
        }
    }

    companion object {
        const val TAG = "KS3Core"
        const val DEFAULT_BUCKET_NAME = "bp-yidian"
        const val DEFAULT_END_POINT = "ks3-cn-beijing.ksyun.com"
        const val VIDEO_SUFFIX = ".mp4"
        const val IMAGE_SUFFIX = ".jpg"
        val INSTANCE: KS3Core by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            KS3Core(context = YdBaseApplication.context)
        }
    }

    init {
        setupClient()
    }

    /**
     * 配置金山云client
     */
    private fun setupClient() {
        client.setConfiguration(Ks3ClientConfiguration.getDefaultConfiguration())
        client.setEndpoint(DEFAULT_END_POINT)
    }

    /**
     * 文件上传
     * @param path 本地文件全路径
     * @param type 文件类型
     * @param scenario 业务场景
     */
    fun uploadObject(
        path: String,
        type: ObjectType,
        scenario: ScenarioType,
        listener: OnKS3TaskListener
    ) {
        ApiService.getKSYunObjectId(object : IGetKSYunObjectIdCallback {
            override fun getKSYunObjectIdSuccess(result: GetKSYunObjectIdBean.Response?) {
                Log.d(
                    TAG,
                    "request getKSYun objectId success, objectId: ${result?.objectId}, bucket: ${result?.bucket}"
                )
                // 执行金山云上传
                val request = PutObjectRequest(
                    result?.bucket,
                    result?.objectId + getObjectKeySuffix(type),
                    File(path)
                )
                request.cannedAcl = CannedAccessControlList.Private
                client.putObject(
                    request,
                    KS3CorePutObjectResponseHandler(
                        result?.bucket,
                        result?.objectId + getObjectKeySuffix(type),
                        listener
                    )
                )
            }

            override fun getKSYunObjectIdFailure(message: String?) {
                Log.e(TAG, "request get KSYun objectId fail, message: $message")
            }
        }, hashMapOf(Pair("scenario", scenario.scenario)))
    }

    /**
     * 文件上传
     * @param path 本地文件全路径
     * @param scenario 业务场景
     */
    fun uploadObject(path: String, scenario: ScenarioType, listener: OnKS3TaskListener) {
        ApiService.getKSYunObjectId(object : IGetKSYunObjectIdCallback {
            override fun getKSYunObjectIdSuccess(result: GetKSYunObjectIdBean.Response?) {
                Log.d(
                    TAG,
                    "request getKSYun objectId success, objectId: ${result?.objectId}, bucket: ${result?.bucket}"
                )
                // 执行金山云上传
                val request = PutObjectRequest(result?.bucket, result?.objectId, File(path))
                request.cannedAcl = CannedAccessControlList.Private
                client.putObject(
                    request,
                    KS3CorePutObjectResponseHandler(result?.bucket, result?.objectId, listener)
                )
            }

            override fun getKSYunObjectIdFailure(message: String?) {
                Log.e(TAG, "request get KSYun objectId fail, message: $message")
            }
        }, hashMapOf(Pair("scenario", scenario.scenario)))
    }

    /**
     * 文件上传
     * @param file 文件实体
     * @param scenario 业务场景
     */
    fun uploadObject(file: File, scenario: ScenarioType, listener: OnKS3TaskListener) {
        ApiService.getKSYunObjectId(object : IGetKSYunObjectIdCallback {
            override fun getKSYunObjectIdSuccess(result: GetKSYunObjectIdBean.Response?) {
                Log.d(
                    TAG,
                    "request getKSYun objectId success, objectId: ${result?.objectId}, bucket: ${result?.bucket}"
                )
                // 执行金山云上传
                val request = PutObjectRequest(result?.bucket, result?.objectId, file)
                request.cannedAcl = CannedAccessControlList.Private
                client.putObject(
                    request,
                    KS3CorePutObjectResponseHandler(result?.bucket, result?.objectId, listener)
                )
            }

            override fun getKSYunObjectIdFailure(message: String?) {
                Log.e(TAG, "request get KSYun objectId fail, message: $message")
            }
        }, hashMapOf(Pair("scenario", scenario.scenario)))
    }

    /**
     * 文件上传
     * @param file 文件实体
     * @param type 文件类型
     * @param scenario 业务场景
     */
    fun uploadObject(
        file: File,
        type: ObjectType,
        scenario: ScenarioType,
        listener: OnKS3TaskListener
    ) {
        ApiService.getKSYunObjectId(object : IGetKSYunObjectIdCallback {
            override fun getKSYunObjectIdSuccess(result: GetKSYunObjectIdBean.Response?) {
                Log.d(
                    TAG,
                    "request getKSYun objectId success, objectId: ${result?.objectId}, bucket: ${result?.bucket}"
                )
                // 执行金山云上传
                val request = PutObjectRequest(
                    result?.bucket,
                    result?.objectId + getObjectKeySuffix(type),
                    file
                )
                request.cannedAcl = CannedAccessControlList.Private
                client.putObject(
                    request,
                    KS3CorePutObjectResponseHandler(
                        result?.bucket,
                        result?.objectId + getObjectKeySuffix(type),
                        listener
                    )
                )
            }

            override fun getKSYunObjectIdFailure(message: String?) {
                Log.e(TAG, "request get KSYun objectId fail, message: $message")
            }
        }, hashMapOf(Pair("scenario", scenario.scenario)))
    }

    /**
     * 获取ObjectKey后缀
     */
    private fun getObjectKeySuffix(type: ObjectType): String {
        return when (type) {
            ObjectType.IMAGE -> IMAGE_SUFFIX
            ObjectType.VIDEO -> VIDEO_SUFFIX
        }
    }

    /**
     * 本地生成ObjectKey
     * 作为Object在云空间的唯一标识
     */
    private fun getLocalObjectKey(name: String, type: ObjectType): String {
        return MD5Util.md5Encrypt32Upper(name + FtDeviceFingerManager.getDeviceFinger()) +
                if (type == ObjectType.VIDEO) VIDEO_SUFFIX else IMAGE_SUFFIX
    }

    /**
     * 调用金山云API后 SDK会回调此函数用于获取必要参数向AppServer请求token
     */
    override fun onCalculateAuth(
        httpMethod: String,
        contentType: String,
        date: String,
        contentMD5: String,
        resource: String,
        headers: String
    ): String? {
        // 此处由APP端向业务服务器发送post请求返回Token
        // 该回调方法运行在非主线程
        Log.d(
            TAG,
            "KSYun calculate auth, httpMethod: $httpMethod, contentType: $contentType, date: $date, contentMD5: $contentMD5, resource: $resource, headers: $headers"
        )
        val requestParams = HashMap<String, String?>()
        requestParams["http_method"] = httpMethod
        requestParams["date"] = date
        requestParams["resource"] = resource
        requestParams["content_md5"] = contentMD5
        requestParams["content_type"] = contentType
        requestParams["headers"] = headers
        return ApiService.getKSYunToken(requestParams)?.result?.token
    }

    /**
     * 业务监听
     */
    interface OnKS3TaskListener {
        fun onTaskStart()
        fun onTaskProgress(progress: Double)
        fun onTaskFinish()
        fun onTaskCancel()
        fun onTaskSuccess(bucket: String?, objectKey: String?)
        fun onTaskFailure(statesCode: Int, message: String?)
    }

    /**
     * 上传对象的类型
     */
    enum class ObjectType {
        VIDEO, IMAGE
    }

    /**
     * 业务场景的类型
     */
    enum class ScenarioType(val scenario: String) {
        // 身份证
        ID_CARD("id_card"),

        // 活体数据
        ALIVE_DETECT("living_data"),

        // 营业执照
        BUSINESS_LICENSE("business_license")
    }

    /**
     * 金山云object上传handler
     */
    class KS3CorePutObjectResponseHandler(
        private val bucket: String?,
        private val objectKey: String?,
        val listener: OnKS3TaskListener
    ) : PutObjectResponseHandler() {

        override fun onTaskProgress(progress: Double) {
            // work thread
            listener.onTaskProgress(progress)
        }

        override fun onTaskFailure(
            statesCode: Int,
            error: Ks3Error?,
            responceHeaders: Array<out Header>?,
            response: String?,
            throwable: Throwable?
        ) {
            Log.e(
                TAG,
                "put object fail:, errorMsg: ${error?.errorMessage}"
            )
            listener.onTaskFailure(statesCode, error?.errorMessage)
        }

        override fun onTaskSuccess(statesCode: Int, responceHeaders: Array<out Header>?) {
            Log.d(TAG, "put object success.")
            listener.onTaskSuccess(bucket, objectKey)
        }

        override fun onTaskStart() {
            listener.onTaskStart()
        }

        override fun onTaskFinish() {
            listener.onTaskFinish()
        }

        override fun onTaskCancel() {
            listener.onTaskCancel()
        }
    }

}
