package com.yidian.bcommon.http

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.yidian.bcommon.app.YdBaseApplication
import com.yidian.bcommon.constant.AppConfig
import com.yidian.bcommon.constant.RunConfig
import com.yidian.bcommon.sdk.BCommonManager
import com.yidian.bcommon.sdk.ClientType
import com.yidian.bcommon.sdk.JudgeClientUtils
import com.yidian.bcommon.services.ZapServiceActionConstants
import com.yidian.bcommon.services.ZapServiceNameConstants
import com.yidian.bcommon.utils.NetWorkUtils
import com.yidian.framework.mobile.xdiamond.SecretUtil
import com.yidian.yac.core.zap.ZapTicket
import com.yidian.yac.ftdevicefinger.core.FtDeviceFingerManager
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import timber.log.Timber
import java.lang.reflect.Type

class HttpParamsUtils {
  companion object {

    private val gson by lazy { Gson() }

    /**
     * 获取公共参数
     * C端通过服务获取
     */
    fun getPublicParamsMap(timeStamp: Long): HashMap<String, String> {
      var paramsMap = hashMapOf<String, String>()
      if (JudgeClientUtils.judgeClient(YdBaseApplication.context.packageName) == ClientType.MERCHANT_B) {
        paramsMap = hashMapOf(
          "appid" to AppConfig.appIdMerchantB,
          "cv" to AppConfig.cv,
          "version" to RunConfig.SERVICE_VERSION,
          "distribution" to AppConfig.distribution,
          "net" to NetWorkUtils.getNetWorkType(YdBaseApplication.context),
          "platform" to AppConfig.platform,
          "device_finger" to getDeviceFinger(),
          "reqid" to getRequestId(timeStamp)
        )
      } else {
        ZapTicket(ZapServiceNameConstants.ClientInfoService).withAction(ZapServiceActionConstants.ActionGetRequestPublicParameters)
          .onResult {
            val result = it.result as JSONObject
            paramsMap = hashMapOf(
              "appid" to result.optString("appid"),
              "cv" to result.optString("cv"),
              "version" to result.optString("version"),
              "distribution" to result.optString("distribution"),
              "net" to result.optString("net"),
              "platform" to result.optString("platform"),
              "device_finger" to getDeviceFinger(),
              "reqid" to getRequestId(timeStamp)
            )
          }.ship()
      }
      Timber.tag(BCommonManager.TAG_HTTP).d("request public params: ${gson.toJson(paramsMap)}")
      return paramsMap
    }

    /**
     * 获取业务参数
     * C端增加user_id
     */
    fun getPrivateParamsMap(paramsMap: HashMap<String, String?>, timeStamp: Long): HashMap<String, String?> {
      return if (RunConfig.IS_ENCRYPT) {
        paramsMap["secret"] = getSignString(getRequestId(timeStamp), timeStamp)
        paramsMap["ts"] = timeStamp.toString()
        // C端身份请求加uid
        BCommonManager.getUid()?.let { paramsMap["user_id"] = it }
        Timber.tag(BCommonManager.TAG_HTTP).d("request private params: ${gson.toJson(paramsMap)}")
        hashMapOf("tok" to SecretUtil.rsaEncrypt(gson.toJson(paramsMap)))
      } else {
        // C端身份请求加uid
        BCommonManager.getUid()?.let { paramsMap["user_id"] = it }
        Timber.tag(BCommonManager.TAG_HTTP).d("request private params: ${gson.toJson(paramsMap)}")
        paramsMap
      }
    }

    /**
     * 获取业务参数（参数为JSONObject的情况）
     * C端增加user_id
     */
    fun getPrivateParamsMap(paramsJson: JSONObject, timeStamp: Long): RequestBody {
      return if (RunConfig.IS_ENCRYPT) {
        paramsJson.put("secret", getSignString(getRequestId(timeStamp), timeStamp))
        paramsJson.put("ts", timeStamp.toString())
        // C端身份请求加uid
        BCommonManager.getUid()?.let { paramsJson.put("user_id", it) }
        Timber.tag(BCommonManager.TAG_HTTP).d("request private params: $paramsJson")
        val jsonObject = JSONObject()
        jsonObject.put("tok", SecretUtil.rsaEncrypt(paramsJson.toString()))
        //指定content type为json类型
        val contentType: MediaType? = "application/json".toMediaTypeOrNull()
        // JSONObject转为RequestBody
        jsonObject.toString().toRequestBody(contentType)
      } else {
        // C端身份请求加uid
        BCommonManager.getUid()?.let { paramsJson.put("user_id", it) }
        Timber.tag(BCommonManager.TAG_HTTP).d("request private params: $paramsJson")
        val contentType: MediaType? = "application/json".toMediaTypeOrNull()
        paramsJson.toString().toRequestBody(contentType)
      }
    }

    /**
     * RSA解密Response
     */
    fun <T> rsaDecryptResult(res: HttpResult<Any?>, type: Type): HttpResult<T> {
      val rsaResult = res.result
      val decodeResult = HttpResult<T>()
      decodeResult.code = res.code
      decodeResult.reason = res.reason
      decodeResult.status = res.status
      if (rsaResult != null) {
        try {// 捕获数据解析异常, 防止T内部的字端解析失败
          if (RunConfig.IS_ENCRYPT) {
            val result = SecretUtil.rsaDecrypt(rsaResult as String)
            Timber.tag(BCommonManager.TAG_HTTP).d("response result: $result")
            val decryptResult = gson.fromJson<HttpDecryptResult<T>>(result, object : TypeToken<HttpDecryptResult<T>>() {}.type)
            val verify = SecretUtil.verifySign(decryptResult.reqid + decryptResult.ts, decryptResult.secret)
            return if (verify) {
              Timber.tag(BCommonManager.TAG_HTTP).d("verify success")
              val resultJson = gson.toJson(decryptResult.data)
              decodeResult.result = gson.fromJson<T>(resultJson, type)
              decodeResult
            } else {
              Timber.tag(BCommonManager.TAG_HTTP).d("verify failure")
              decodeResult
            }
          } else {
            val resultJson = gson.toJson(rsaResult)
            Timber.tag(BCommonManager.TAG_HTTP).d("response result: $resultJson")
            decodeResult.result = gson.fromJson<T>(resultJson, type)
            return decodeResult
          }
        } catch (e: Exception) {
          e.printStackTrace()
        }
      }
      return decodeResult
    }

    /**
     * 获取设备指纹
     */
    private fun getDeviceFinger(): String {
      return FtDeviceFingerManager.getDeviceFinger() ?: ""
    }

    /**
     * 获取唯一请求标识
     * 规则：appId + "_" + deviceFinger + "_" + timeStamp
     */
    private fun getRequestId(timeStamp: Long): String {
      return StringBuilder().append(BCommonManager.getAppId()).append('_').append(getDeviceFinger()).append('_').append(timeStamp)
        .toString()
    }

    /**
     * 获取签名串
     * 规则: reqId + timeStamp
     */
    private fun getSignString(reqId: String, timeStamp: Long): String {
      return SecretUtil.sign(StringBuilder().append(reqId).append(timeStamp).toString()).toString()
    }
  }
}
