package cn.yyxx.eyuancomm.base.network

import android.content.Context
import android.text.TextUtils
import cn.yyxx.eyuancomm.base.SdkDrive
import cn.yyxx.eyuancomm.base.entity.ResultInfo
import cn.yyxx.eyuancomm.base.utils.Logger
import cn.yyxx.support.FileUtils
import cn.yyxx.support.JsonUtils
import cn.yyxx.support.ResUtils
import cn.yyxx.support.StrUtils
import cn.yyxx.support.encryption.Base64Utils
import cn.yyxx.support.encryption.HexUtils
import cn.yyxx.support.encryption.Md5Utils
import cn.yyxx.support.volley.MultipartRequest
import cn.yyxx.support.volley.VolleySingleton
import cn.yyxx.support.volley.entity.FileEntity
import cn.yyxx.support.volley.source.*
import cn.yyxx.support.volley.source.toolbox.HttpHeaderParser
import cn.yyxx.support.volley.source.toolbox.JsonObjectRequest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONException
import org.json.JSONObject
import java.io.File
import java.io.IOException

/**
 * @author #Suyghur.
 * Created on 2021/06/21
 */
object VolleyRequest {

    private const val MAX_TIMEOUT = 10 * 1000

    fun post(context: Context, host: String, jsonObject: JSONObject, isCommJob: Boolean , callback: (ResultInfo) -> Unit) {
        try {
            val time = System.currentTimeMillis().toString()
            val randomKey = time + StrUtils.getRandomString(16)
            val rawKey = Md5Utils.encodeByMD5(randomKey)
            val aesKey = Md5Utils.encodeByMD5(rawKey + StrUtils.reverseString(rawKey))
            val hexP = if (isCommJob) {
                SdkDrive.instance.invokeCommJob(aesKey.substring(8, 24), jsonObject.toString())
            } else {
                SdkDrive.instance.invokeCoreJob(aesKey.substring(8, 24), jsonObject.toString())
            }
            val tmp = HexUtils.hexString2Bytes(hexP)
            val p = Base64Utils.encode(tmp)

            Logger.d("请求路由 : ${jsonObject["route_path"]}")
            Logger.d("请求参数 : $jsonObject")
            Logger.logHandler("请求路由 : ${jsonObject["route_path"]}\n")
            Logger.logHandler("请求参数 : $jsonObject\n")
            val obj = JSONObject()
            obj.put("p", p)
            obj.put("ts", rawKey)
            Logger.d("$obj")
            Logger.d("host: $host")

            val request = object : JsonObjectRequest(Method.POST, host, obj, Response.Listener {
                val resultInfo = ResultInfo()
                resultInfo.code = -1
                resultInfo.msg = "接口请求异常"
                it?.apply {
                    try {
                        resultInfo.code = it.getInt("code")
                        resultInfo.msg = it.getString("msg")
                        resultInfo.data = if (JsonUtils.hasJsonKey(it, "data")) {
                            it.getJSONObject("data").parseResponse()
                        } else {
                            "{}"
                        }
                    } catch (e: JSONException) {
                        e.printStackTrace()
                    }
                }
                it.put("data", JSONObject(resultInfo.data))
                Logger.d("返回信息 : $it")
                Logger.logHandler("返回信息 : $it\n")
                callback(resultInfo)
            }, Response.ErrorListener {
                it?.apply {
                    Logger.e("postByVolley onErrorResponse : $it")
                    callback(getErrorResultInfo(context))
                }
            }) {
                override fun getHeaders(): MutableMap<String, String> {
                    val headers = HashMap<String, String>()
                    headers["Accept"] = "application/json"
                    headers["Content-Type"] = "application/json;charset=UTF-8"
                    return headers
                }
            }
            //设置超时时间
            request.retryPolicy = DefaultRetryPolicy(MAX_TIMEOUT, 1, 1.0f)
            VolleySingleton.getInstance(context.applicationContext).addToRequestQueue(context.applicationContext, request)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun downloadImageFile(context: Context, url: String, callback: (Int, String) -> Unit) {
        val cacheFolder = File(context.getExternalFilesDir("cache")!!.absolutePath)
        if (!cacheFolder.exists()) {
            cacheFolder.mkdirs()
        }
        val fileName = Md5Utils.encodeByMD5(url)
        val filePath = "$cacheFolder/$fileName"
        Logger.d(filePath)
        if (File(filePath).exists()) {
            callback(-1, "image has been cached locally")
            return
        }
        val request: Request<ByteArray> = object : Request<ByteArray>(Method.GET, url, Response.ErrorListener {
            callback(-1, it.getErrorMessage(context))
        }) {
            override fun parseNetworkResponse(response: NetworkResponse): Response<ByteArray> {
                return try {
                    if (response.data == null) {
                        Response.error(ParseError(response))
                    } else {
                        Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response))
                    }
                } catch (e: OutOfMemoryError) {
                    e.printStackTrace()
                    Response.error(ParseError(e))
                }
            }

            override fun deliverResponse(response: ByteArray) {
                Logger.d("volley download image file success, start to save file ...")
                try {
                    GlobalScope.launch(Dispatchers.IO) {
                        Logger.d("with io coroutines do save file")
                        FileUtils.saveFile(filePath, response)
                    }
                    callback(0, "download file success, path: $filePath")
                } catch (e: IOException) {
                    e.printStackTrace()
                    callback(-1, ParseError(e).getErrorMessage(context))
                }
            }
        }

        VolleySingleton.getInstance(context.applicationContext).addToRequestQueue(context.applicationContext, request)
    }

    fun uploadFile(context: Context, url: String, file: File, jsonObject: JSONObject, isCommJob: Boolean, callback: (ResultInfo) -> Unit) {
        if (!file.exists()) {
            Logger.e("${file.name}不存在请检查")
            return
        }
        val resultInfo = ResultInfo()
        resultInfo.code = -1
        resultInfo.msg = "接口请求异常"

        val time = System.currentTimeMillis().toString()
        val randomKey = time + StrUtils.getRandomString(16)
        val rawKey = Md5Utils.encodeByMD5(randomKey)
        val aesKey = Md5Utils.encodeByMD5(rawKey + StrUtils.reverseString(rawKey))

        val hexP = if (isCommJob) {
            SdkDrive.instance.invokeCommJob(aesKey.substring(8, 24), jsonObject.toString())
        } else {
            SdkDrive.instance.invokeCoreJob(aesKey.substring(8, 24), jsonObject.toString())
        }
        val tmp = HexUtils.hexString2Bytes(hexP)
        val p = Base64Utils.encode(tmp)

        Logger.d("请求地址 : $url")
        Logger.d("请求参数 : $jsonObject")
        Logger.logHandler("请求地址 : $url\n")
        Logger.logHandler("请求参数 : $jsonObject\n")
        val params = HashMap<String, Any>()
        params["p"] = p
        params["ts"] = rawKey

        Logger.d("上传文件: ${file.name} ...")
        val fileEntity = FileEntity()
        fileEntity.mName = "upload_file"
        fileEntity.mFileName = file.name
        fileEntity.mFile = file

        kotlin.runCatching {
            val request = MultipartRequest(url, params, fileEntity, {
                with(JSONObject(it)) {
                    resultInfo.code = getInt("code")
                    resultInfo.msg = getString("msg")
                }
                callback(resultInfo)
            }) {
                if (TextUtils.isEmpty(it.localizedMessage)) {
                    resultInfo.msg = it.localizedMessage!!
                }
                callback(resultInfo)
            }
            VolleySingleton.getInstance(context.applicationContext).addToRequestQueue(context.applicationContext, request)
        }.onFailure {
            if (TextUtils.isEmpty(it.localizedMessage)) {
                resultInfo.msg = it.localizedMessage!!
            }
            callback(resultInfo)
        }
    }

    private fun JSONObject.parseResponse(): String {
        try {
            val ts = getString("ts")
            val aesKey = Md5Utils.encodeByMD5(ts + StrUtils.reverseString(ts))
            val base64P = getString("p")
            val tmp = Base64Utils.decode(base64P)
            val p = HexUtils.bytes2HexString(tmp)
            return SdkDrive.instance.parseJob(aesKey.substring(8, 24), p)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        return ""
    }

    private fun VolleyError.getErrorMessage(context: Context): String {
        return if (!TextUtils.isEmpty(message)) {
            message!!
        } else {
            ResUtils.getResString(context, "yyxx_network_tv_error")
        }
    }

    private fun VolleyError.getErrorResultInfo(context: Context): ResultInfo {
        val resultInfo = ResultInfo()
        resultInfo.code = 400
        resultInfo.msg = ""
        networkResponse?.apply {
            resultInfo.code = statusCode
            if (!TextUtils.isEmpty(message)) {
                resultInfo.msg = message!!
            } else {
                resultInfo.msg = ResUtils.getResString(context, "yyxx_network_tv_error")
            }
        }
        resultInfo.data = ""
        return resultInfo
    }
}