package com.ydl.ydlnet

import android.annotation.SuppressLint
import android.content.Context
import com.google.gson.reflect.TypeToken
import com.ydl.ydlnet.builder.config.OkHttpConfig
import com.ydl.ydlnet.builder.cookie.CookieJarImpl
import com.ydl.ydlnet.builder.cookie.store.CookieStore
import com.ydl.ydlnet.builder.factory.ApiFactory
import com.ydl.ydlnet.cache.RxCache
import com.ydl.ydlnet.cache.data.CacheResult
import com.ydl.ydlnet.cache.stategy.CacheStrategy
import com.ydl.ydlnet.client.download.DownloadHelper
import com.ydl.ydlnet.client.upload.UploadHelper
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.ResponseBody

/**
 * Created by haorui on 2019-09-02 .
 * Des: YDL 网络请求工具类
 */
class YDLHttpUtils {


    /**
     * 必须在全局Application先调用，获取context上下文，否则缓存无法使用
     *
     * @param app Application
     */
    fun init(app: Context): YDLHttpUtils {
        context = app
        return this
    }


    fun config(): ApiFactory {
        checkInitialize()
        return ApiFactory.getInstance()
    }

    companion object {

        @SuppressLint("StaticFieldLeak")
        private var instance: YDLHttpUtils? = null
        @SuppressLint("StaticFieldLeak")
        private var context: Context? = null

        fun getInstance(): YDLHttpUtils {
            if (instance == null) {
                synchronized(YDLHttpUtils::class.java) {
                    if (instance == null) {
                        instance = YDLHttpUtils()
                    }
                }

            }
            return instance!!
        }

        /**
         * 获取全局上下文
         */
        fun getContext(): Context? {
            checkInitialize()
            return context
        }

        /**
         * 检测是否调用初始化方法
         */
        private fun checkInitialize() {
            if (context == null) {
                throw ExceptionInInitializerError("请先在全局Application中调用 YDLHttpUtils.getInstance().init(this) 初始化！")
            }
        }


        /**
         * 使用全局参数创建请求
         *
         * @param cls Class
         * @param <K> K
         * @return 返回
        </K> */
        fun <K> obtainApi(cls: Class<K>): K {
            return ApiFactory.getInstance().createApi(cls)
        }

        /**
         * 下载文件
         *
         * @param fileUrl 地址
         * @return ResponseBody
         */
        fun downloadFile(fileUrl: String): Observable<ResponseBody> {
            return DownloadHelper.downloadFile(fileUrl)
        }

        /**
         * 上传单张图片
         *
         * @param uploadUrl 地址
         * @param filePath  文件路径
         * @return ResponseBody
         */
        fun uploadImg(uploadUrl: String, filePath: String): Observable<ResponseBody> {
            return UploadHelper.uploadImage(uploadUrl, filePath)
        }

        /**
         * 上传多张图片
         *
         * @param uploadUrl 地址
         * @param filePaths 文件路径
         * @return ResponseBody
         */
        fun uploadImages(uploadUrl: String, filePaths: List<String>): Observable<ResponseBody> {
            return UploadHelper.uploadImages(uploadUrl, filePaths)
        }

        /**
         * 上传多张图片
         *
         * @param uploadUrl 地址
         * @param fileName  后台接收文件流的参数名
         * @param paramsMap 参数
         * @param filePaths 文件路径
         * @return ResponseBody
         */
        fun uploadImagesWithParams(
            uploadUrl: String,
            fileName: String,
            paramsMap: Map<String, Any>,
            filePaths: List<String>
        ): Observable<ResponseBody> {
            return UploadHelper.uploadFilesWithParams(uploadUrl, fileName, paramsMap, filePaths)
        }

        /**
         * 获取全局的CookieJarImpl实例
         */
        private val cookieJar: CookieJarImpl
            get() = OkHttpConfig.getInstance().okHttpClient.cookieJar() as CookieJarImpl

        /**
         * 获取全局的CookieStore实例
         */
        private val cookieStore: CookieStore
            get() = cookieJar.cookieStore

        /**
         * 获取所有cookie
         */
        val allCookie: List<Cookie>
            get() {
                val cookieStore = cookieStore
                return cookieStore.allCookie
            }

        /**
         * 获取某个url所对应的全部cookie
         */
        fun getCookieByUrl(url: String): List<Cookie> {
            val cookieStore = cookieStore
            val httpUrl = HttpUrl.parse(url)
            return cookieStore.getCookie(httpUrl)
        }


        /**
         * 移除全部cookie
         */
        fun removeAllCookie() {
            val cookieStore = cookieStore
            cookieStore.removeAllCookie()
        }

        /**
         * 移除某个url下的全部cookie
         */
        fun removeCookieByUrl(url: String) {
            val httpUrl = HttpUrl.parse(url)
            val cookieStore = cookieStore
            cookieStore.removeCookie(httpUrl)
        }


        /**
         * 需要缓存数据时使用此方法，strategy缓存规则默认优先网络
         */
        inline fun <reified T> transformCache(key: String): ObservableTransformer<T, T> {
            return ObservableTransformer {
                it.compose<CacheResult<T>>(RxCache.getDefault().transformObservable(key, object : TypeToken<T>() {}.type, CacheStrategy.firstRemote()))
                    .map { response ->
                        response.data
                    }
            }
        }
    }
}
