package com.doverfuelingsolutions.issp.api

import com.doverfuelingsolutions.issp.R
import com.doverfuelingsolutions.issp.api.basic.RetrofitUtil
import com.doverfuelingsolutions.issp.api.dto.*
import com.doverfuelingsolutions.issp.api.entity.DefaultParams
import com.doverfuelingsolutions.issp.api.entity.NozzleInfo
import com.doverfuelingsolutions.issp.api.entity.ParametersBean
import com.doverfuelingsolutions.issp.api.service.ServiceStation
import com.wayne.www.waynelib.util.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPKeys
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.wayne.www.waynelib.fdc.message.DeviceClass
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

object FuelInfoApi {

    private var serviceStation: ServiceStation = serviceMaker()

    /**
     * 获取泵+枪信息，并且其中的补全残缺信息
     */
    suspend fun requestPumpInfo() = suspendCoroutine<DFSResult<List<NozzleInfo>>> {
        GlobalScope.launch(Dispatchers.IO) {
            val resultApi = getApiInfo(WayneApiConfig.Api_GetPumpsLayout)
            if (resultApi.success && resultApi.data != null) {
                val resultPumpList = requestPumpList(resultApi.data.Path)
                if (!resultPumpList.success || resultPumpList.data == null) {
                    it.resume(DFSResult.fail(resultPumpList.message))
                    return@launch
                } else if (resultPumpList.data.isEmpty()) {
                    it.resume(DFSResult.success(emptyList()))
                    return@launch
                }

                val nozzles = arrayListOf<NozzleInfo>()
                val barcodeHashMap = HashMap<Int, ResultBarcode>()
                resultPumpList.data.forEach { pump ->
                    pump.Nozzles.forEach { nozzle ->
                        val barcode = nozzle.ProductBarcode
                        val barcodeInfo: ResultBarcode? = if (barcodeHashMap.containsKey(barcode)) {
                            barcodeHashMap[barcode]
                        } else {
                            val resultBarcodeInfo = SystemApi.barcodeName(barcode)
                            if (resultBarcodeInfo.success && resultBarcodeInfo.data != null) {
                                barcodeHashMap[barcode] = resultBarcodeInfo.data
                                resultBarcodeInfo.data
                            } else {
                                null
                            }
                        }
                        val n = NozzleInfo(
                            pump.PumpId,
                            nozzle.LogicalId,
                            nozzle.SiteLevelNozzleId,
                            nozzle.ProductBarcode,
                            barcodeInfo?.ItemName ?: "",
                            barcodeInfo?.Id ?: "")
                        nozzles.add(n)
                    }
                }
                it.resume(DFSResult.success(nozzles))
            } else {
                it.resume(DFSResult.fail(resultApi.message))
            }
        }
    }

    /**
     * 获取累计数信息
     */
    suspend fun accumulationInfo(dc: DeviceClass) = suspendCoroutine<DFSResult<ResultAccumulationInfo>> {
        GlobalScope.launch(Dispatchers.IO) {
            val resultApi = getApiInfo(WayneApiConfig.Api_AccumulationInfo)
            if (resultApi.success && resultApi.data != null) {
                val params = RequestBody.create(MediaType.parse("application/json"), "{\"Parameters\":[{\"Name\":\"releasetoken\",\"Value\":\"${dc.releaseTokenElement}\"}]}")
                serviceStation.postBody(resultApi.data.Path, params).enqueue(object : Callback<ResponseBody> {
                    override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                        val code = response.code()
                        val body = response.body()?.string()
                        if (code == 200 && body != null) {
                            val obj = Gson().fromJson<Array<ResultAccumulationInfo>>(body, object : TypeToken<Array<ResultAccumulationInfo>>() {}.type)
                            it.resume(DFSResult.success(obj[0]))
                            return
                        }
                        it.resume(DFSResult.fail(R.string.return_data_error))
                    }

                    override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                        DFSLog.e(t)
                        it.resume(DFSResult.fail(t.message.toString()))
                    }
                })
            } else {
                it.resume(DFSResult.fail(resultApi.message))
            }
        }
    }

    /**
     * 获取泵+枪信息
     */
    private suspend fun requestPumpList(url: String) = suspendCoroutine<DFSResult<Array<ResultPumpInfo>>> {
        val params = RequestBody.create(MediaType.parse("application/json"), "{\"Parameters\":[]}")
        serviceStation.postBody(url, params).enqueue(object : Callback<ResponseBody> {
            override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                val code = response.code()
                val body = response.body()?.string()
                if (code == 200 && body != null) {
                    val obj = Gson().fromJson<Array<ResultPumpInfo>>(body, (object : TypeToken<Array<ResultPumpInfo>>() {}).type)
                    it.resume(DFSResult.success(obj))
                    return
                }
                it.resume(DFSResult.fail(R.string.return_data_error))
            }

            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                DFSLog.e("FuelInfoApi.requestPumpList.onFailure", t)
                it.resume(DFSResult.fail(t.message.toString()))
            }
        })
    }

    /**
     * 【FCC2.0】获取泵+枪信息，并且其中的补全残缺信息
     */
    suspend fun requestPumpInfoFromFCC2(): DFSResult<List<NozzleInfo>> {
        return suspendCoroutine {
            serviceStation.getNozzleInfo().enqueue(object : Callback<ResponseBody> {
                override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                    try {
                        val code = response.code()
                        val body = response.body()?.string()
                        if (code == 200 && body != null) {
                            val obj = Gson().fromJson<List<ResultPumpInfoFCC2>>(body, object : TypeToken<List<ResultPumpInfoFCC2>>() {}.type)
                            GlobalScope.launch {
                                val nozzles = arrayListOf<NozzleInfo>()
                                val barcodeHashMap = HashMap<Int, ResultBarcode>()

                                obj.forEach { pump ->
                                    pump.Nozzles.forEach { nozzle ->
                                        val barcode = nozzle.ProductBarcode
                                        val barcodeInfo: ResultBarcode? = if (barcodeHashMap.containsKey(barcode)) {
                                            barcodeHashMap[barcode]
                                        } else {
                                            val resultBarcodeInfo = SystemApi.barcodeName(barcode)
                                            if (resultBarcodeInfo.success && resultBarcodeInfo.data != null) {
                                                barcodeHashMap[barcode] = resultBarcodeInfo.data
                                                resultBarcodeInfo.data
                                            } else {
                                                null
                                            }
                                        }
                                        val n = NozzleInfo(
                                            pump.PumpId,
                                            nozzle.LogicalId,
                                            nozzle.SiteLevelNozzleId,
                                            nozzle.ProductBarcode,
                                            barcodeInfo?.ItemName ?: "",
                                            barcodeInfo?.Id ?: "")
                                        nozzles.add(n)
                                    }
                                }
                                it.resume(DFSResult.success(nozzles))
                            }
                        } else {
                            it.resume(DFSResult.fail(response.message()))
                        }
                    } catch (e: Exception) {
                        it.resume(DFSResult.fail(e.message.toString()))
                    }
                }

                override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                    it.resume(DFSResult.fail(t.message.toString()))
                }
            })
        }
    }

    /**
     * 【FCC2.0】获取累计数信息
     */
    suspend fun accumulationInfoFromFCC2(dc: DeviceClass): DFSResult<ResultAccumulationInfo> {
        return suspendCoroutine {
            val bean = ParametersBean().apply {
                Value = dc.releaseTokenElement
            }
            serviceStation.accumulationInfo(DefaultParams(listOf(bean))).enqueue(object : Callback<List<ResultAccumulationInfo>> {
                override fun onResponse(call: Call<List<ResultAccumulationInfo>>, response: Response<List<ResultAccumulationInfo>>) {
                    val code = response.code()
                    val body = response.body()
                    if (code == 200 && body != null && body.isNotEmpty()) {
                        it.resume(DFSResult.success(body[0]))
                        return
                    }

                    it.resume(DFSResult.fail(R.string.fail_get_accumulation))
                }

                override fun onFailure(call: Call<List<ResultAccumulationInfo>>, t: Throwable) {
                    DFSLog.e("FuelInfoApi.accumulationInfo.onFailure", t)
                    it.resume(DFSResult.fail(R.string.fail_get_accumulation))
                }
            })
        }
    }

    /* Wayne FCC3.0 后，不能使用静态 Url 请求接口，必须查询得到动态 Url 后调用 */
    private val apiInfoListType = (object : TypeToken<List<ResultApiInfo>>() {}).type
    private suspend fun getApiInfo(type: String) = suspendCoroutine<DFSResult<ResultApiInfo>> {
        val params = RequestBody.create(MediaType.parse("application/json"), "[\"webApi\", [\"IfsfFdcServer\"]]")
        serviceStation.postBody(WayneApiConfig.URL_SERVICE_DISCOVER, params)
            .enqueue(object : Callback<ResponseBody> {
                override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                    val code = response.code()
                    val body = response.body()?.string()
                    if (code == 200 && body != null) {
                        val obj = Gson().fromJson<List<ResultApiInfo>>(body, apiInfoListType)
                        val api = obj.find { item -> item.ApiName.equals(type, true) }
                        if (api != null) {
                            it.resume(DFSResult.success(api))
                            return
                        }
                    }
                    it.resume(DFSResult.fail(R.string.return_data_error))
                }

                override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                    DFSLog.e("FuelInfoApi.getApiInfo.onFailure", t)
                    it.resume(DFSResult.fail(t.message.toString()))
                }
            })
    }

    private fun serviceMaker(): ServiceStation {
        val ip = SPUtil.getString(SPKeys.FUEL_IP)
        val port = SPUtil.getString(SPKeys.FUEL_PORT)
        val url = "http://$ip:$port"
        return RetrofitUtil.getGsonBuilder().baseUrl(url).build().create(ServiceStation::class.java)
    }

    fun generateService() {
        serviceStation = serviceMaker()
    }
}