package com.rc.httpcore.net

import android.os.AsyncTask
import android.util.Log
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.rc.httpcore.HttpClient
import com.rc.httpcore.HttpConfig
import com.rc.httpcore.exception.NetException
import com.rc.httpcore.interceptor.NullToEmptyInterceptor
import com.rc.httpcore.interceptor.TokenHeaderInterceptor
import com.rc.httpcore.vo.CommonDataResponse
import com.rc.httpcore.vo.response.FileRespBean
import io.reactivex.functions.Consumer
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import java.io.File
import java.util.concurrent.TimeUnit

/**
 * info
 *
 * @author ReiChin_
 */
class UploadTask(
    private val onProgress: Consumer<Int>? = null,
    private val onSuccess: Consumer<FileRespBean>,
    private val onFailed: Consumer<Throwable?>
) :
    AsyncTask<String, Int, UploadTask.UploadResult>() {

    companion object {
        const val TYPE_SUCCESS: Int = 1
        const val TYPE_FAILED: Int = 2
    }

    override fun doInBackground(vararg params: String?): UploadResult {
        if (params.isNullOrEmpty()) return UploadResult(
            TYPE_FAILED,
            throwable = IllegalArgumentException("params is null or empty")
        )

        try {
            val file = File(params[0]!!)
            val fileBody =
                RequestBody.create(okhttp3.MediaType.parse("application/octet-stream"), file)
            val filePart = MultipartBody.Part.createFormData("file", file.name, fileBody)

            val requestBody = ProgressMultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addPart(filePart)
                .addProgressListener { currentBytes, contentLength ->
                    val progress: Int = (currentBytes * 100 / contentLength).toInt()
                    Log.i(
                        "RcLog",
                        "currentBytes:${currentBytes}, contentLength:${contentLength}, progress=${progress}%"
                    )
                    publishProgress(if (progress >= 100) 99 else progress)
                }
                .build()

            val request = Request.Builder()
                .addHeader("Transfer-Encoding", "chunked")
                .url("${HttpConfig.API_BASE_URL}${HttpConfig.BASE_PATH_BASE}file/upload")
                .post(requestBody)
                .build()

            val okHttpClient = OkHttpClient.Builder()
                .readTimeout(HttpClient.TIMEOUT_DEFAULT, TimeUnit.SECONDS) // 设置读取超时时间
                .connectTimeout(HttpClient.TIMEOUT_DEFAULT, TimeUnit.SECONDS) // 设置请求超时时间
                .writeTimeout(HttpClient.TIMEOUT_DEFAULT, TimeUnit.SECONDS) // 设置写入超时时间
                .callTimeout(5, TimeUnit.MINUTES) // 上传超时时间：5分钟
                .addNetworkInterceptor(TokenHeaderInterceptor())
//                .retryOnConnectionFailure(false) // 设置出现错误进行重新连接
                .build()

            val response = okHttpClient.newCall(request).execute()
            if (response.isSuccessful) {

                val responseData = response.body()?.string()

                val typeOfT = object : TypeToken<CommonDataResponse<FileRespBean>>() {}.type
                val result =
                    Gson().fromJson<CommonDataResponse<FileRespBean>>(responseData, typeOfT)
                return if (result.isSuccess()) {
                    publishProgress(100)
                    UploadResult(TYPE_SUCCESS, data = result.data)
                } else {
                    UploadResult(TYPE_FAILED, throwable = NetException(result.code, result.msg))
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            return UploadResult(TYPE_FAILED, throwable = e)
        }
        return UploadResult(TYPE_FAILED, throwable = RuntimeException("上传失败"))
    }

    override fun onProgressUpdate(vararg values: Int?) {
        val progress = values[0]
        progress?.let {
            onProgress?.accept(it)
        }
    }

    override fun onPostExecute(result: UploadResult?) {
        when (result?.status) {
            TYPE_SUCCESS -> onSuccess.accept(result.data!!)
            TYPE_FAILED -> onFailed.accept(result.throwable)
            else -> Unit
        }
    }

    data class UploadResult(
        val status: Int?,
        val data: FileRespBean? = null,
        val throwable: Throwable? = null
    )

}