package com.yidianling.ydlcommon.custom.http

//import com.yidianling.common.tools.RxAppTool
//import com.yidianling.common.tools.RxDeviceTool
import android.annotation.SuppressLint
import android.text.TextUtils
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.yidianling.ydlcommon.core.base.BaseApplication
import com.yidianling.common.tools.LogUtil
import com.yidianling.common.tools.RxAppTool
import com.yidianling.common.tools.RxDeviceTool
import com.yidianling.ydlcommon.BuildConfig
import com.yidianling.ydlcommon.custom.constant.YdlConstants
import com.yidianling.ydlcommon.custom.data.YdlDataManager
import com.yidianling.ydlcommon.custom.router.YdlCommonRouterManager
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import okio.Buffer
import okio.BufferedSink
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.security.cert.X509Certificate
import java.util.*
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
import javax.net.ssl.X509TrustManager


/**
 * Retrofit 提供类，提供单例的 Retrofit 对象
 *
 * author : Zhangwenchao
 * e-mail : zhangwch@yidianling.com
 * time   : 2018/01/29
 */
class RetrofitProvider private constructor() {

    companion object {

        //        private val BASE_URL_TEST = "https://testapp2.yidianling.com/v3/"
//        private val BASE_URL = "https://app2.yidianling.com/v3/"
        private const val AUTHORIZATION_NAME = "Authorization"
        private const val SESSION_KEY = "dc59cf294f37d237c1f06240568ffe21"
        private const val YDL = "Ydl"

        private const val UID = "uid"
        private const val FFROM = "ffrom"
        private const val IS_FROM_APP = "isFromApp"
        private const val OS_BUILD = "osBuild"
        private const val TS = "ts"
        private const val VERSION = "version"
        private const val TOKEN = "accessToken"

        private fun getInstance(): RetrofitProvider {
            return Holder.INSTANCE
        }

        // 调用此方法获取 Retrofit 对象
        fun getRetrofit(): Retrofit {
            return getInstance().getRetrofit()
        }

        //销毁对象
        fun clearRetrofit() {
            return getInstance().clearRetrofit()
        }

    }

    private fun clearRetrofit() {
        retrofit = null
    }

    private var retrofit: Retrofit? = null

    private fun getRetrofit(): Retrofit {
        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                    .baseUrl(com.yidianling.ydlcommon.custom.http.YdlRetrofitUtils.POST)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(okHttpClick())
                    .build()
        }
        return retrofit!!
    }

    private fun okHttpClick(): OkHttpClient {
        var build = OkHttpClient.Builder()
        build.retryOnConnectionFailure(false)
        try {
            build.addInterceptor(
                com.yidianling.ydlcommon.custom.http.PostCacheInterceptor(
                    com.yidianling.ydlcommon.custom.http.DiskLruCacheHelper(
                        BaseApplication.getApp()
                    )
                )
            )
        } catch (e: Exception) {

        }
        build.addInterceptor(commonParams())
        build.addInterceptor(requestHead())
        build.connectTimeout(15, TimeUnit.SECONDS)
        build.readTimeout(15, TimeUnit.SECONDS)
        build.writeTimeout(15, TimeUnit.SECONDS)
        //设置okhttp的连接池保活时间为1秒
        //build.connectionPool(ConnectionPool(5,1,TimeUnit.SECONDS))

        //使用自定义线程池方案，防止线程数超出最大限制造成OOM（华为部分机型线程数限制300）
        build.dispatcher(Dispatcher(ThreadPoolExecutor(2, 20, 20L, TimeUnit.SECONDS, LinkedBlockingQueue<Runnable>(64), ThreadPoolExecutor.DiscardOldestPolicy())))

        val xtm = trustManager()
        val factory = com.yidianling.ydlcommon.custom.http.YDLSSLFactory.getSocketFactory();
        if (BuildConfig.DEBUG) {
            build.addInterceptor(HttpLoggingInterceptor {
                //打印retrofit日志
                LogUtil.i("RetrofitLog", "retrofitBack = $it")
            }.setLevel(HttpLoggingInterceptor.Level.BODY))
            build.addNetworkInterceptor(StethoInterceptor())
        }

        if (factory != null) {
            build.sslSocketFactory(factory, com.yidianling.ydlcommon.custom.http.YDLSSLFactory.getSafeTrustManager())
                    .hostnameVerifier { _, _ -> true }
        }
        return build.build()
    }

    // 添加公共参数
    private fun commonParams(): Interceptor {
        return Interceptor {
            val request = it.request()
            var body = request.body()

            if (body is FormBody) {
                val bodyBuild = FormBody.Builder()
                for (i in 0 until body.size()) {
                    val name = body.name(i)
                    val value = body.value(i)
                    // 去除假参数和值为空的参数
                    if (YdlConstants.HOLDER_PARAM != name && !TextUtils.isEmpty(value)) {
                        bodyBuild.addEncoded(name, value)
                    }
                }
                bodyBuild.addEncoded(FFROM, YdlDataManager.getRam().getChannelName())
                        .addEncoded(IS_FROM_APP, "1")
                        .addEncoded(
                            OS_BUILD, """${RxDeviceTool.getBuildBrandModel()},${RxDeviceTool.getSDKVersionName()},${RxAppTool.getAppVersionName(
                                BaseApplication.getApp())}""")
                        .addEncoded(TS, (System.currentTimeMillis() / 1000).toString())
                        .addEncoded(
                            VERSION, RxAppTool.getAppVersionName(
                                BaseApplication.getApp()))
                val loginBean = YdlCommonRouterManager.getYdlCommonRoute()?.getUserInfo()
                if (loginBean != null) {
                    bodyBuild.addEncoded(UID, loginBean.userId)
                    bodyBuild.addEncoded(TOKEN, loginBean.token)
                }

                body = bodyBuild.build()
            } else if (body is MultipartBody) {

            }
            it.proceed(request.newBuilder().post(body!!).build())
        }
    }


    private data class Param(val name: String, val value: String)

    // 添加请求头
    private fun requestHead(): Interceptor {
        return Interceptor {
            val request = it.request()
            val body = request.body()
            val paramsString = StringBuilder()
            val params = ArrayList<Param>()
            if (body is FormBody) {
                (0 until body.size()).mapTo(destination = params) {
                    Param(
                        body.name(it),
                        body.value(it)
                    )
                }

            } else if (body is MultipartBody) {
                for (part in body.parts()) {
                    if ("text/plain; charset=utf-8" == part.body().contentType()!!.toString()) {
                        val headerStr = part.headers()!!.toString()
                        val name = headerStr.split("\"\\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0].split("=\"".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
                        val buffer = Buffer()
                        part.body().writeTo(buffer as BufferedSink)
                        val value = buffer.readUtf8()
                        params.add(Param(name, value))
                    }
                }
            }
            params.sortWith(Comparator { o1, o2 ->
                val res = o1.name.compareTo(o2.name)
                when {
                    res == 0 -> 0
                    res > 0 -> -1
                    else -> 1
                }
            })
            params.withIndex().forEach { (index, param) ->
                if (index != 0) paramsString.append("&")
                paramsString.append("${param.name}=${param.value}")
            }
            paramsString.append(SESSION_KEY)
            val head = "$YDL ${EncryptUtils.encryptMD5ToString(
                paramsString.toString()
            )}"
            it.proceed(request.newBuilder()
                    .header(AUTHORIZATION_NAME, head)
//                    .header("Content-Type","application/json")
                    .build())
        }
    }

    private fun log(): Interceptor {
        return HttpLoggingInterceptor {
            when {
                BuildConfig.DEBUG -> LogUtil.d("RetrofitLog", it)
            }
        }.setLevel(HttpLoggingInterceptor.Level.BODY)
    }

    @SuppressLint("TrustAllX509TrustManager")
    private fun trustManager(): X509TrustManager {
        return object : X509TrustManager {
            override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

            override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {}

            override fun getAcceptedIssuers(): Array<X509Certificate?> {
                return arrayOfNulls(0)
            }
        }
    }

    private object Holder {
        val INSTANCE = RetrofitProvider()
    }

}