package com.abbidot.baselibrary.network.base

import com.abbidot.baselibrary.network.exception.ErrorCode
import com.abbidot.baselibrary.network.exception.NetworkErrorCodeException
import com.abbidot.baselibrary.network.exception.NetworkException
import com.abbidot.baselibrary.network.interceptor.CommonRequestInterceptor
import com.abbidot.baselibrary.network.interceptor.CommonResponseInterceptor
import com.abbidot.baselibrary.network.interceptor.DoubleDefault0Adapter
import com.abbidot.baselibrary.network.interceptor.StringNullAdapter
import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil
import com.google.gson.GsonBuilder
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.reflect.ParameterizedType
import java.util.concurrent.TimeUnit

/**
 * 网络请求封装
 */
abstract class BaseNetworkApi<I>(private val baseUrl: String) : IService<I> {

    protected val service: I by lazy {
        getRetrofit().create(getServiceClass())
    }

    protected open fun getRetrofit(): Retrofit {
        //添加gson解析null拦截器
        val gson = GsonBuilder().registerTypeAdapter(String::class.java, StringNullAdapter())
            .registerTypeAdapter(Double::class.java, DoubleDefault0Adapter()).create()

        return Retrofit.Builder().baseUrl(baseUrl).client(getOkHttpClient())
            .addConverterFactory(GsonConverterFactory.create(gson)).build()
    }

    private fun getServiceClass(): Class<I> {
        val genType = javaClass.genericSuperclass as ParameterizedType
        return genType.actualTypeArguments[0] as Class<I>
    }

    private fun getOkHttpClient(): OkHttpClient {
        val okHttpClient = getCustomOkHttpClient()
        if (null != okHttpClient) {
            return okHttpClient
        }
        return defaultOkHttpClient
    }

    protected open fun getCustomOkHttpClient(): OkHttpClient? {
        return null
    }

    protected open fun getCustomInterceptor(): Interceptor? {
        return null
    }

    protected suspend fun <T> getResult(block: suspend () -> BaseResponse<T>): Result<T> {
        for (i in 1..RETRY_COUNT) {
            try {
                val response = block()
                //处理”response.code != OK“情况
                if (response.code != ErrorCode.OK) {

                    //处理信用卡支付返回结果
                    if (response.code == ErrorCode.ERROR) {
                        val message = response.message
                        if (message == "支付失败") {
                            return Result.success("${ErrorCode.CREDIT_CARD_PAY_FAIL}" as T)
                        }
                    }
                    //设备已被绑定
                    else if (response.code == ErrorCode.DEVICE_HAS_BIND) {
                        throw NetworkErrorCodeException.of(response.code, response.message + "")
                    }

                    throw NetworkErrorCodeException.of(
                        response.code, "exception code is ${response.code},response code not 200"
                    )
                }
                //适用于只管请求成功(T=String),不需要处理结果数据
                val data = response.data
                if (null == data || data == "") {
                    //处理信用卡支付返回结果
                    val message = response.message
                    if (message == "支付成功") {
                        return Result.success("${ErrorCode.CREDIT_CARD_PAY_SUCCESS}" as T)
                    }
                    //throw NetworkException.of(ErrorCode.VALUE_IS_NULL, "response data is null")
                    return Result.success("${response.code}" as T)
                }
                return Result.success(response.data)
            } catch (throwable: Throwable) {
                LogUtil.e("BaseNetworkApi-->Throwable", throwable.message.toString())
                if (throwable is NetworkException) {
                    return Result.failure(throwable)
                } else if (throwable is NetworkErrorCodeException) {
                    return Result.failure(throwable)
                }
                if ((throwable is HttpException && throwable.code() == ErrorCode.UNAUTHORIZED)) {
                    // 这里刷新token，然后重试
                }
            }
        }
        return Result.failure(NetworkException.of(ErrorCode.VALUE_IS_NULL, "unknown"))
    }

    companion object {
        const val TAG = "BaseNetworkApi"

        //失败重试请求次数
        private const val RETRY_COUNT = 1

        //请求超时时间
        private const val REQUEST_TIMEOUT = 40L
        private val defaultOkHttpClient by lazy {
            val builder = OkHttpClient.Builder().callTimeout(REQUEST_TIMEOUT, TimeUnit.SECONDS)
                .connectTimeout(REQUEST_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(REQUEST_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(REQUEST_TIMEOUT, TimeUnit.SECONDS).retryOnConnectionFailure(true)
            //添加拦截器
            builder.addInterceptor(CommonRequestInterceptor())
            builder.addInterceptor(CommonResponseInterceptor())
            if (AppUtils.isDebug()) {
                val loggingInterceptor = HttpLoggingInterceptor()
                loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
                builder.addInterceptor(loggingInterceptor)
            }

            builder.build()
        }
    }
}