package com.doverfuelingsolutions.issp.utils.sp

import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import androidx.annotation.NonNull
import androidx.preference.PreferenceManager
import com.doverfuelingsolutions.issp.api.WayneApiConfig
import com.doverfuelingsolutions.issp.api.dto.ResultBarcode
import com.doverfuelingsolutions.issp.data.entity.WayneOrderRecord
import com.doverfuelingsolutions.issp.utils.DeviceUtil
import com.wayne.www.waynelib.util.log.DFSLog
import com.doverfuelingsolutions.issp.utils.thread.ThreadUtil
import com.wayne.www.waynelib.fdc.message.DeviceClass
import com.wayne.www.waynelib.webservice.entity.PosTrx
import java.io.*

object SPUtil {

    private lateinit var instance: SharedPreferences

    fun init(context: Context) {
        instance = PreferenceManager.getDefaultSharedPreferences(context)
        setDefaultValue()
    }

    fun printData() {
//        setObject(SPKeys.ORDER_LOCK, arrayListOf<String>("3-1-1","3-2-2","3-3-3"))
//        setObject(SPKeys.ORDER_UNCLEARED, arrayListOf<String>("3-1-1","3-2-2","3-3-3","3-4-4","3-5-5","3-6-6"))

        val lockList = getLockOrderList()
        val unClearList = getUnclearedOrderList()

        DFSLog.i("【测试】锁单个数：${lockList.size}",lockList.map { it })
        DFSLog.i("【测试】未消单个数：${unClearList.size}",unClearList.map { it })
    }

    /** 油站一直反馈有时锁单时得返回订单页再支付才能正常支付，支付完得单有时还存在。看日志是因为在锁单与消单时
     * 4秒后没收到响应（但fcc日志显示有回复），可能是返回首页时，自动解锁单与消单时占用太多线程，将数据清理一下
     * 试试。另外加日志看看有没有收到fcc回复（在 FdcClient 的 FireToXmlMessageHandler 中 ）
     */
    fun removeLockOrderAndClearOrder() {
        val list = getUnclearedOrderList()
        val unClearList = arrayListOf<String>()
        if (list.size > 5) { //只保存最新的 5 单
            for (index in list.size - 5 until list.size) {
                unClearList.add(list[index])
            }
        }
        setObject(SPKeys.ORDER_LOCK, arrayListOf<String>())
//        setObject(SPKeys.ORDER_LOCK, getFakeLockList())
        setObject(SPKeys.ORDER_UNCLEARED, unClearList)
    }

    // 假数据，给一百个待解锁订单
    fun getFakeLockList():ArrayList<String>{
        val locks = arrayListOf<String>()
        for (index in 1 .. 100) {
            locks.add("$index-$index-$index")
        }
        return locks
    }

    fun getString(key: String, defaultValue: String = "") = instance.getString(key, defaultValue) ?: ""
    fun putString(key: String, value: String) {
        instance.edit().run {
            putString(key, value)
            apply()
        }
    }

    fun getBoolean(key: String, defaultValue: Boolean = false) = instance.getBoolean(key, defaultValue)

    private fun <T : Serializable> setObject(key: String, @NonNull obj: T) {
        ThreadUtil.io {
            try {
                if (key.isBlank()) throw IllegalArgumentException("SP key must not be blank or empty.")

                val byteArrayOutputStream = ByteArrayOutputStream()
                val objectOutputStream = ObjectOutputStream(byteArrayOutputStream)
                objectOutputStream.writeObject(obj)
                val string = String(Base64.encode(byteArrayOutputStream.toByteArray(), Base64.DEFAULT))
                byteArrayOutputStream.close()
                objectOutputStream.close()
                putString(key, string)

            } catch (e: Exception) {
                DFSLog.e(e)
            }
        }
    }

    private inline fun <reified T> getObject(key: String): T? {
        val string = getString(key)
        if (string.isBlank()) return null

        val byteArrayInputStream = ByteArrayInputStream(Base64.decode(string.toByteArray(), Base64.DEFAULT))
        val objectInputStream = ObjectInputStream(byteArrayInputStream)
        val obj = objectInputStream.readObject()
        return if (obj is T) obj else null
    }

    private fun setDefaultValue() {
        val firstLaunch = instance.getBoolean(SPKeys.FIRST_LAUNCH, true)

        /**    为了在测试时可在 DeviceUtil.generateSerialNumber 中直接修改设备编码，在这里将
         *  DeviceUtil.generateSerialNumber生成的设备编码存入 SP
         */
        instance.edit().run {
            putString(SPKeys.SN, DeviceUtil.generateSerialNumber())

            //添加升级服务信息
            putString(SPKeys.UPDATEL_IP, WayneApiConfig.DOMAIN_DEFAULT_RELEASE)
            putString(SPKeys.UPDATE_PORT, WayneApiConfig.PORT_ASSETS_DEFAULT)
            commit()
        }

        if (!firstLaunch) return

        instance.edit().run {
            putBoolean(SPKeys.FIRST_LAUNCH, false)

            putString(SPKeys.SN, DeviceUtil.generateSerialNumber())
            putString(SPKeys.SN_RAW, DeviceUtil.hardwareSerialNumber())

            putString(SPKeys.SERVER_DOMAIN, WayneApiConfig.DOMAIN_DEFAULT)
            putString(SPKeys.SERVER_PORT_BASE, WayneApiConfig.PORT_BASE_DEFAULT)
            putString(SPKeys.SERVER_PORT_TRX, WayneApiConfig.PORT_TRX_DEFAULT)
            putString(SPKeys.SERVER_PORT_CONFIG, WayneApiConfig.PORT_CONFIG_DEFAULT)
            putString(SPKeys.SERVER_PORT_ASSETS, WayneApiConfig.PORT_ASSETS_DEFAULT)

            putString(SPKeys.MIDDLE_IP, WayneApiConfig.MIDDLE_IP_DEFAULT)
            putString(SPKeys.MIDDLE_PORT, WayneApiConfig.MIDDLE_PORT_DEFAULT)
            putString(SPKeys.MIDDLE_WORKSTATION_ID, WayneApiConfig.MIDDLE_WORKSTATION_ID)

            putString(SPKeys.FUEL_IP, WayneApiConfig.FUEL_IP_DEFAULT)
            putString(SPKeys.FUEL_PORT, WayneApiConfig.FUEL_PORT_DEFAULT)

//            putString(SPKeys.UPDATEL_IP, WayneApiConfig.DOMAIN_DEFAULT)
//            putString(SPKeys.UPDATE_PORT, WayneApiConfig.PORT_ASSETS_DEFAULT)

            putString(SPKeys.ORDER_CHOOSE, "all")

            commit()
        }
    }

    /***** 业务相关部分 *****/
    /**
     * DC 类的唯一标识，用于标记订单（而非存下整个 DC），目的是节省存储空间和提高速度
     */
    private fun getDeviceClassSymbol(dc: DeviceClass): String = "${dc.pumpNo}-${dc.transactionSeqNo}-${dc.releaseTokenAttribute}"

    /**
     * 订单列表：读取
     */
    fun getOrderListByPump(pumpId: Int): ArrayList<DeviceClass> {
        return getObject<ArrayList<DeviceClass>>("${SPKeys.ORDER_UNSETTLED}-$pumpId") ?: ArrayList()
    }
    /**
     * 订单列表：存储
     */
    fun setOrderListByPump(pumpId: Int, orderList: List<DeviceClass>) {
        DFSLog.v("set order_unsettled-$pumpId")
        setObject("${SPKeys.ORDER_UNSETTLED}-$pumpId", ArrayList(orderList))
    }
    /**
     * 订单列表：分 pump 存储REMOVE ORDER_LOCK START
     */
    fun setAllOrderList(orderList: List<DeviceClass>) {
        val map = HashMap<Int, ArrayList<DeviceClass>>()
        orderList.forEach {
            val pumpId = it.pumpNo
            if (!map.containsKey(pumpId)) {
                map[pumpId] = arrayListOf(it)
            } else {
                map[pumpId]?.add(it)
            }
        }
        map.forEach {
            setObject("${SPKeys.ORDER_UNSETTLED}-${it.key}", ArrayList(it.value))
        }
    }

    /**
     * 油品代码信息：读取
     */
    fun getBarcodeInfo(barcode: Int): ResultBarcode? = getObject<ResultBarcode>(SPKeys.FUEL_BARCODE + barcode)
    /**
     * 油品代码信息：写入
     */
    fun setBarcodeInfo(barcode: Int, obj: ResultBarcode) = setObject(SPKeys.FUEL_BARCODE + barcode, obj)

    /**
     * 云订单：读取本地列表
     */
    private fun getWayneOrderList(): ArrayList<WayneOrderRecord> {
        return getObject<ArrayList<WayneOrderRecord>>(SPKeys.ORDER_GENERATED) ?: ArrayList()
    }
    /**
     * 云订单：添加到本地
     */
    fun addWayneOrder(dc: DeviceClass, posTrx: PosTrx) {
        val orderList = getWayneOrderList()
        orderList.add(WayneOrderRecord(
            getDeviceClassSymbol(dc),
            posTrx,
            System.currentTimeMillis()
        ))
        val symbol = getDeviceClassSymbol(dc)
        DFSLog.v("add order_generated:$symbol")
        setObject(SPKeys.ORDER_GENERATED, orderList)
    }
    /**
     * 云订单：从本地列表移除
     */
    fun removeWayneOrder(dc: DeviceClass) {
        val symbol = getDeviceClassSymbol(dc)
        removeWayneOrder(symbol)
    }
    fun removeWayneOrder(symbol: String) {
        val orderList = getWayneOrderList()
        val order = orderList.find { it.dc == symbol }
        DFSLog.v("REMOVE ORDER_GENERATED START $symbol")
        if (order != null) {
            DFSLog.v("remove order_generated $symbol")
            orderList.remove(order)
            setObject(SPKeys.ORDER_GENERATED, orderList)
        }
    }
    /**
     * 云订单：从本地列表查找
     */
    fun findWayneOrder(dc: DeviceClass): PosTrx? {
        val symbol = getDeviceClassSymbol(dc)
        val orderList = getWayneOrderList()
        val order = orderList.find { it.dc == symbol }
        if (order != null) {
            return order.posTrx
        }
        return null
    }
    /**
     * 云订单：本地列表移除过期的
     */
    fun removeExpiredWayneOrder() {
        val orderList = getWayneOrderList()
        if (orderList.isEmpty()) return

        val notExpireList = ArrayList<WayneOrderRecord>()
        orderList.forEach {
            if (!it.isExpire()) {
                notExpireList.add(it)
            }
        }
        if (orderList.size != notExpireList.size) {
            DFSLog.v("remove expired order_generated")
            setObject(SPKeys.ORDER_GENERATED, notExpireList)
        }
    }

    /**
     * 订单锁定：获取在本设备上锁定的订单列表
     */
    fun getLockOrderList(): ArrayList<String> {
        return getObject<ArrayList<String>>(SPKeys.ORDER_LOCK) ?: ArrayList()
    }
    /**
     * 订单锁定：锁定一笔订单
     */
    fun addLockOrder(dc: DeviceClass) {
        val symbol = getDeviceClassSymbol(dc)
        val list = getLockOrderList()
        //超过一定数量要删除最先的 ，可能自助机解锁不成功后后台帮忙解锁，那么这笔单在自助机就会一直解锁不成功（因为订单已经解锁了）
        if (list.size > 5) list.removeAt(0)
        DFSLog.v("ADD ORDER_LOCK START $symbol,the size of lock order list is ${list.size}")
        if (!list.contains(symbol)) {
            DFSLog.v("add order_lock $symbol")
            list.add(symbol)
            setObject(SPKeys.ORDER_LOCK, list)
        }
    }
    /**
     * 订单锁定：解锁一笔订单
     */
    fun removeLockOrder(dc: DeviceClass) = removeLockOrder(getDeviceClassSymbol(dc))
    private fun removeLockOrder(symbol: String) {
        val list = getLockOrderList()
        DFSLog.v("REMOVE ORDER_LOCK START $symbol")
        if (list.isNotEmpty() && list.contains(symbol)) {
            DFSLog.v("remove order_lock $symbol")
            list.remove(symbol)
            setObject(SPKeys.ORDER_LOCK, list)
        }
    }
    /**
     * 订单锁定：判断订单是否被当前设备锁定的
     */
    fun isLockByThis(dc: DeviceClass): Boolean {
        val list = getLockOrderList()
        val symbol = getDeviceClassSymbol(dc)
        return list.contains(symbol)
    }
    /**
     * 订单锁定：新的锁定订单列表
     */
    fun replaceLockOrderList(orderList: List<String>) {
        DFSLog.v("replace lock")
        setObject(SPKeys.ORDER_LOCK, ArrayList(orderList))
    }
    fun replaceLockOrderListByDC(orderList: List<DeviceClass>) {
        val sList = orderList.map { getDeviceClassSymbol(it) }
        replaceLockOrderList(sList)
    }

    /**
     * 消除订单：待消除的订单列表
     */
    fun getUnclearedOrderList(): ArrayList<String> {
        return getObject<ArrayList<String>>(SPKeys.ORDER_UNCLEARED) ?: ArrayList()
    }
    /**
     * 消除订单：添加
     */
    fun addUnclearedOrder(dc: DeviceClass) {
        val orderList = getUnclearedOrderList()
        if (orderList.size > 5) orderList.removeAt(0)
        val symbol = getDeviceClassSymbol(dc)
        DFSLog.v("ADD ORDER_UNCLEARED START $symbol,the size of uncleared order list is ${orderList.size}")
        if (!orderList.contains(symbol)) {
            orderList.add(symbol)
            setObject(SPKeys.ORDER_UNCLEARED, orderList)
        }
    }
    /**
     * 消除订单：移除
     */
    fun removeUnclearedOrder(dc: DeviceClass) = removeUnclearedOrder(getDeviceClassSymbol(dc))
    private fun removeUnclearedOrder(symbol: String) {
        val list = getUnclearedOrderList()
        if (list.isNotEmpty() && list.contains(symbol)) {
            list.remove(symbol)
            setObject(SPKeys.ORDER_UNCLEARED, list)
        }
    }
    /**
     * 消除订单：新的锁定订单列表
     */
    fun replaceUnclearedOrderList(orderList: List<String>) {
        setObject(SPKeys.ORDER_UNCLEARED, ArrayList(orderList))
    }
}