package com.qimai.android.fetch.config

import android.text.TextUtils
import com.qimai.android.fetch.interceptors.HeaderInterceptor
import com.qimai.android.fetch.interceptors.NetCacheInterceptor
import com.qimai.android.fetch.interceptors.NoNetCacheInterceptor
import com.qimai.android.fetch.tool.SSLUtils
import com.qimai.android.widgetlib.toast.HolderContext
import com.safframework.http.interceptor.LoggingInterceptor
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import java.io.File
import java.io.InputStream
import java.util.concurrent.TimeUnit
import javax.net.ssl.HostnameVerifier


class OkHttpConfig private constructor(builder: Builder) {


    private var instance: OkHttpConfig? = null
    private var okHttpClient: OkHttpClient? = null
    private var isDebug: Boolean = builder.isDebug
    private var isCache: Boolean = builder.isCache
    private var cacheTime = builder.cacheTime
    private var noNetCacheTime = builder.noNetCacheTime
    private var cachePath: String? = builder.cachePath
    private var cacheMaxSize: Long = builder.cacheMaxSize
    private var readTimeout: Long = builder.readTimeout
    private var writeTimeout: Long = builder.writeTimeout
    private var connectTimeout: Long = builder.connectTimeout
    private var bksFile: InputStream? = builder.bksFile
    private var password: String? = builder.password
    private var certificates: Array<out InputStream>? = builder.certificates
    private var interceptors: Array<out Interceptor>? = builder.interceptors
    private var buildHeadersListener: HeaderConfig? = builder.buildHeadersListener
    private var hostnameVerifier: HostnameVerifier? = builder.hostnameVerifier
    private var okHttpClientBuilder: OkHttpClient.Builder = builder.okHttpClientBuilder

    fun okHttpClient(): OkHttpClient {
        return okHttpClientBuilder.build()
    }

    class Builder {
        internal var okHttpClientBuilder: OkHttpClient.Builder = OkHttpClient.Builder()
        private val defaultCacheSize = (1024 * 1024 * 100).toLong()
        internal var isDebug: Boolean = false
        internal var isCache: Boolean = false
        internal var cacheTime = 60
        internal var noNetCacheTime = 10
        internal var cachePath: String? = null
        internal var cacheMaxSize: Long = 0
        internal var readTimeout: Long = 0
        internal var writeTimeout: Long = 0
        internal var connectTimeout: Long = 0
        internal var bksFile: InputStream? = null
        internal var password: String? = null
        internal var certificates: Array<out InputStream>? = null
        internal var interceptors: Array<out Interceptor>? = null
        internal var buildHeadersListener: HeaderConfig? = null
        internal var hostnameVerifier: HostnameVerifier? = null
        private var defaultCachePath: String? = null

        private val defaultTimeout: Long = 10

        fun headers(buildHeadersListener: HeaderConfig) = apply {
            this.buildHeadersListener = buildHeadersListener
        }

        fun debug(isDebug: Boolean) = apply {
            this.isDebug = isDebug;
        }

        fun cache(isCache: Boolean) = apply { this.isCache = isCache }

        fun cacheTime(cacheTime: Int) = apply {
            this.cacheTime = cacheTime
        }

        fun noNetCacheTime(noNetCacheTime: Int) = apply {
            this.noNetCacheTime = noNetCacheTime
        }

        fun cahchePath(cachePath: String) = apply {
            this.cachePath = cachePath
        }


        fun cacheMaxSize(cacheMaxSize: Long) = apply {
            this.cacheMaxSize = cacheMaxSize
        }


        fun readTimeOut(readTimeout: Long) = apply {
            this.readTimeout = readTimeout
        }


        fun writeTimeOut(writeTimeout: Long) = apply {
            this.writeTimeout = writeTimeout
        }

        fun connectTimeOut(connectTimeout: Long) = apply {
            this.connectTimeout = connectTimeout
        }

        fun intercepteors(vararg interceptors: Interceptor) = apply {
            this.interceptors = interceptors
        }


        fun sslSocketFactory(vararg certificates: InputStream) = apply {
            this.certificates = certificates
        }


        fun sslSocketFactory(
            bksFile: InputStream,
            password: String,
            vararg certificates: InputStream
        ) = apply {
            this.bksFile = bksFile
            this.password = password
            this.certificates = certificates
        }

        fun hostnameVerifier(hostnameVerifier: HostnameVerifier) = apply {
            this.hostnameVerifier = hostnameVerifier
        }


        fun build(): OkHttpConfig {
            setCacheConfig()
            setHeadersConfig()
            setSslConfig()
            setHostnameVerifier()
            addInterceptors()
            setTimeout()
            setDebugConfig()

            return OkHttpConfig(this)
        }


        private fun addInterceptors() {
            if (null != interceptors) {
                for (interceptor in interceptors!!) {
                    okHttpClientBuilder.addInterceptor(interceptor)
                }
            }
        }

        /**
         * 配置开发环境
         */
        private fun setDebugConfig() {
            if (isDebug) {
                val loggingInterceptor =
                    LoggingInterceptor.Builder()
                        .loggable(true)
                        .request()
                        .requestTag("Request")
                        .response()
                        .responseTag("Response") //.hideVerticalLine()// 隐藏竖线边框
                        .build()
                okHttpClientBuilder.addInterceptor(loggingInterceptor)
            }
        }


        /**
         * 配置headers
         */
        private fun setHeadersConfig() {
            if (buildHeadersListener != null) {
                okHttpClientBuilder.addInterceptor(object : HeaderInterceptor() {
                    override fun buildHeaders(): Map<String, String> {
                        return buildHeadersListener!!.buildHeaders()
                    }
                })
            }
        }


        /**
         * 配置缓存
         */
        private fun setCacheConfig() {
            val externalCacheDir = HolderContext.getContext().externalCacheDir ?: return
            defaultCachePath = externalCacheDir.path + "/RxHttpCacheData"
            if (isCache) {
                val cache: Cache = if (!TextUtils.isEmpty(cachePath) && cacheMaxSize > 0) {
                    Cache(File(cachePath!!), cacheMaxSize)
                } else {
                    Cache(File(defaultCachePath!!), defaultCacheSize)
                }

                okHttpClientBuilder
                    .cache(cache)
                    .addInterceptor(
                        NoNetCacheInterceptor(
                            noNetCacheTime
                        )
                    )
                    .addNetworkInterceptor(
                        NetCacheInterceptor(
                            cacheTime
                        )
                    )
            }
        }

        /**
         * 配置超时信息
         */
        private fun setTimeout() {
            okHttpClientBuilder.readTimeout(
                if (readTimeout == 0L) defaultTimeout else readTimeout,
                TimeUnit.SECONDS
            )
            okHttpClientBuilder.writeTimeout(
                if (writeTimeout == 0L) defaultTimeout else writeTimeout,
                TimeUnit.SECONDS
            )
            okHttpClientBuilder.connectTimeout(
                if (connectTimeout == 0L) defaultTimeout else connectTimeout,
                TimeUnit.SECONDS
            )
            okHttpClientBuilder.retryOnConnectionFailure(true)
        }

        /**
         * 配置证书
         */
        private fun setSslConfig() {
            var sslParams: SSLUtils.SSLParams? = if (null == certificates) {
                //信任所有证书,不安全有风险
                SSLUtils.getSslSocketFactory()
            } else {
                if (null != bksFile && !TextUtils.isEmpty(password)) {
                    //使用bks证书和密码管理客户端证书（双向认证），使用预埋证书，校验服务端证书（自签名证书）
                    SSLUtils.getSslSocketFactory(bksFile, password, *certificates!!)
                } else {
                    //使用预埋证书，校验服务端证书（自签名证书）
                    SSLUtils.getSslSocketFactory(*certificates!!)
                }
            }

            okHttpClientBuilder.sslSocketFactory(
                sslParams?.sSLSocketFactory!!,
                sslParams.trustManager
            )
        }

        private fun setHostnameVerifier() {
            if (null == hostnameVerifier) {
                okHttpClientBuilder.hostnameVerifier(SSLUtils.UnSafeHostnameVerifier)
            } else {
                okHttpClientBuilder.hostnameVerifier(hostnameVerifier!!)
            }
        }
    }


}

