package com.cr.network

import com.cr.data.CrUtil
import okhttp3.Headers
import okhttp3.MediaType
import okhttp3.MultipartBody
import okhttp3.MultipartBody.Companion.ALTERNATIVE
import okhttp3.MultipartBody.Companion.DIGEST
import okhttp3.MultipartBody.Companion.FORM
import okhttp3.MultipartBody.Companion.MIXED
import okhttp3.MultipartBody.Companion.PARALLEL
import okhttp3.RequestBody
import okhttp3.internal.toImmutableList
import okio.*
import okio.ByteString.Companion.encodeUtf8
import java.util.*
import kotlin.jvm.JvmOverloads

/**
 * 操作系统：MAC系统
 * 创建者：王成
 * 创建日期：2023/8/28 14:55
 * 描述：多内容上传body
 */
class CrProgressMultipartRequestBody @JvmOverloads constructor(
    requestBody: MultipartBody,
    listener:ICallback?= null
) : RequestBody(){
    /**
     * 进度接口
     */
    interface ICallback{
        // todo: 2023/8/28 进度回调
        fun onProgress(currentBytes:Long,totalBytes:Long)

        // todo: 2023/8/28 错误回调
        fun onFailed(error:String)
    }

    private var requestBody:MultipartBody?= null // define: 2023/8/28 body定义
    private var listener:ICallback?= null // define: 2023/8/28 回调监听
    private var bufferedSink:BufferedSink?= null // define: 2023/8/28 sink缓冲区

    private var bytesWritten:Long = 0  // define: 2023/8/28 写入长度
    private var contentLength:Long = 0 // define: 2023/8/28 总长度

    /**
     * 初始化
     */
    init {
        this.requestBody = requestBody
        this.listener = listener
        this.contentLength = this.requestBody!!.contentLength()
    }

    /**
     * 覆写 获取内容长度
     * @return MediaType?
     */
    override fun contentType(): MediaType? {
        return requestBody?.contentType()
    }

    /**
     * 覆写 获取内容长度
     * @return Long
     */
    override fun contentLength(): Long {
        return requestBody!!.contentLength()
    }

    /**
     * 覆写 写入内容
     * @param sink BufferedSink
     */
    override fun writeTo(sink: BufferedSink) {
        if(bufferedSink == null){
            bufferedSink = ProgressBufferSink(sink).buffer()
        }
        requestBody?.writeTo(bufferedSink!!)
        bufferedSink?.flush()
    }

    /**
     * 内部类 注意 不是嵌套类 内部类需要使用inner限制
     * @constructor
     */
    inner class ProgressBufferSink @JvmOverloads constructor(
        delegate:Sink
    ) : ForwardingSink(delegate) {
        /**
         * 覆写 写入方法
         * @param source Buffer
         * @param byteCount Long
         */
        override fun write(source: Buffer, byteCount: Long) {
            super.write(source, byteCount)
            bytesWritten += byteCount
            listener?.onProgress(bytesWritten,contentLength)
        }
    }

    class Builder @JvmOverloads constructor() {
        private var type = MIXED
        private val parts = mutableListOf<MultipartBody.Part>()
        private var listener:ICallback?= null

        /**
         * 设置类型
         * @param type MediaType 类型
         * @return Builder
         */
        fun setType(type: MediaType) = apply {
            this.type = type
        }

        /**
         * 添加body部分
         * @param body RequestBody body
         * @return Builder
         */
        fun addPart(body: RequestBody) = apply {
            addPart(MultipartBody.Part.create(body))
        }

        /**
         * 添加body部分
         * @param headers Headers? 头部
         * @param body RequestBody 体
         * @return Builder
         */
        fun addPart(headers: Headers?, body: RequestBody) = apply {
            addPart(MultipartBody.Part.create(headers, body))
        }

        /**
         * 添加数据
         * @param name String 数据名称
         * @param value String 数据内容
         * @return Builder
         */
        fun addFormDataPart(name: String, value: String) = apply {
            addPart(MultipartBody.Part.createFormData(name, value))
        }

        /**
         * 添加文件数据
         * @param name String 数据名称
         * @param filename String? 文件名称
         * @param body RequestBody 体
         * @return Builder
         */
        fun addFormDataPart(name: String, filename: String?, body: RequestBody) = apply {
            addPart(MultipartBody.Part.createFormData(name, filename, body))
        }

        /**
         * 添加body部分
         * @param part Part 部分
         * @return Builder
         */
        private fun addPart(part: MultipartBody.Part) = apply {
            parts.add(part)
            return this
        }

        /**
         * 添加监听
         * @param listener ICallback? 监听
         */
        fun addListener(listener: ICallback?){
            this.listener = listener
        }

        /**
         * 编译
         * @return MultipartBody
         */
        fun build(): CrProgressMultipartRequestBody {
            check(parts.isNotEmpty()) { "Multipart body must have at least one part." }
            var builder = MultipartBody.Builder().setType(type)
            for (part in parts){
                builder.addPart(part)
            }
            return CrProgressMultipartRequestBody(builder.build(),listener)
        }
    }
}