package com.doverfuelingsolutions.issp.api

import com.doverfuelingsolutions.issp.R
import com.doverfuelingsolutions.issp.api.basic.RetrofitUtil
import com.doverfuelingsolutions.issp.api.dto.DFSResult
import com.doverfuelingsolutions.issp.api.dto.ResultNozzleInfo
import com.doverfuelingsolutions.issp.api.entity.NozzleInfo
import com.doverfuelingsolutions.issp.api.service.ServiceStation
import com.doverfuelingsolutions.issp.utils.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPKeys
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

object FuelInfoApi {

    private val retrofit: Retrofit by lazy {
        val ip = SPUtil.getString(SPKeys.FUEL_IP)
        val port = SPUtil.getString(SPKeys.FUEL_PORT)
        val url = "http://$ip:$port"
        RetrofitUtil.getGsonBuilder().baseUrl(url).build()
    }
    private val serviceStation: ServiceStation by lazyOf(retrofit.create(ServiceStation::class.java))

    suspend fun getNozzleInfo() = suspendCoroutine<DFSResult<List<NozzleInfo>>> {
        GlobalScope.launch(Dispatchers.IO) {
            val resultNozzleList = getNozzleData()
            if (!resultNozzleList.success || resultNozzleList.data == null) {
                it.resume(DFSResult.fail(resultNozzleList.message))
                return@launch
            } else if (resultNozzleList.data.isEmpty()) {
                it.resume(DFSResult.success(emptyList()))
                return@launch
            }

            val localBarcodeMap = getLocalBarcodeMap().toMutableMap()
            var isLocalAdd = false
            val nozzleInfoList = arrayListOf<NozzleInfo>()
            for (pump in resultNozzleList.data) {
                for (nozzle in pump.Nozzles) {
                    val localName = localBarcodeMap[nozzle.ProductBarcode]
                    val name: String = if (localName != null && localName.isNotEmpty()) {
                        localName
                    } else {
                        val resultBarcodeInfo = CloudApi.barcodeName(nozzle.ProductBarcode)
                        if (resultBarcodeInfo.success && resultBarcodeInfo.data != null && resultBarcodeInfo.data.IsFuelItem) {
                            localBarcodeMap[nozzle.ProductBarcode] = resultBarcodeInfo.data.ItemName
                            isLocalAdd = true
                            resultBarcodeInfo.data.ItemName
                        } else {
                            ""
                        }
                    }
                    nozzleInfoList.add(NozzleInfo(pump.PumpId, nozzle.SiteLevelNozzleId, nozzle.ProductBarcode, name))
                }
            }
            if (isLocalAdd) setLocalBarcodeMap(localBarcodeMap)

            nozzleInfoList.sortBy { it.siteId }
            it.resume(DFSResult.success(nozzleInfoList))
        }
    }

    private fun getLocalBarcodeMap(): Map<Int, String> {
        return mutableMapOf<Int, String>().apply {
            val localBarcodeList = SPUtil.getString(SPKeys.FUEL_BARCODE)
            localBarcodeList.split(",").forEach {
                val kv = it.split("=")
                if (kv.size == 2) put(kv[0].toInt(), kv[1])
            }
        }
    }

    private fun setLocalBarcodeMap(map: Map<Int, String>) {
        SPUtil.putString(SPKeys.FUEL_BARCODE, map.entries.joinToString(",") { "${it.key}=${it.value}" })
    }

    private suspend fun getNozzleData() = suspendCoroutine<DFSResult<Array<ResultNozzleInfo>>> {
        serviceStation.getNozzleInfo().enqueue(object : Callback<Array<ResultNozzleInfo>> {
            override fun onResponse(call: Call<Array<ResultNozzleInfo>>, response: Response<Array<ResultNozzleInfo>>) {
                val code = response.code()
                val body = response.body()
                DFSLog.v("FuelInfoApi.getNozzleData.onResponse", code, body.toString())
                if (code == 200 && body != null) {
                    it.resume(DFSResult.success(body))
                    return
                }
                it.resume(DFSResult.fail(R.string.return_data_error))
            }

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