package com.gamedog.vididin.manager

import com.ama.core.architecture.util.SpUtil
import com.gamedog.vididin.beans.BaseRecord
import com.gamedog.vididin.beans.RECORD_CASH_WITHDRAW
import com.gamedog.vididin.beans.RecordCash
import com.gamedog.vididin.beans.RecordCashShow
import com.gamedog.vididin.beans.RecordGold
import com.gamedog.vididin.beans.RecordGoldShow
import com.gamedog.vididin.beans.RecordZero
import com.gamedog.vididin.beans.RecordZeroShow
import com.gamedog.vididin.beans.toShowBean
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_ONGOING
import com.gamedog.vididin.manager.WithdrawManager.Companion.TRANSACTION_STATE_SUCCESS
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.util.concurrent.locks.ReentrantLock


class RecordsManager private constructor() {
    private val mCashHelper by lazy { CashRecordHelper() }
    private val mGoldHelper by lazy { GoldRecordHelper() }
    private val mZeroHelper by lazy { ZeroRecordHelper() }

    companion object {
        @Volatile
        private var instance: RecordsManager? = null

        fun instance(): RecordsManager {
            return instance ?: synchronized(this) {
                instance ?: RecordsManager().also {
                    instance = it
                }
            }
        }
    }


    fun appendCashRecord(newRecord: RecordCash) {
        mCashHelper.addRecord(newRecord)
    }

    fun updateCashRecord(updateRecord: RecordCash) {
        mCashHelper.updateRecord(updateRecord)
    }

    fun appendGoldRecord(newRecord: RecordGold) {
        mGoldHelper.addRecord(newRecord)
    }

    fun appendZeroRecord(newRecord: RecordZero) {
        mZeroHelper.addRecord(newRecord)
    }

    fun getCashRecords() : List<RecordCashShow> {
        val resultList = mutableListOf<RecordCashShow>()
        val dataList = mCashHelper.getRecordList()
        dataList.forEach {
            resultList.add(it.toShowBean())
        }
        return resultList.toList()
    }

    fun getGoldRecords() : List<RecordGoldShow> {
        val resultList = mutableListOf<RecordGoldShow>()
        val dataList = mGoldHelper.getRecordList()
        dataList.forEach {
            resultList.add(it.toShowBean())
        }
        return resultList.toList()
    }

    fun getZeroRecords() : List<RecordZeroShow> {
        val resultList = mutableListOf<RecordZeroShow>()
        val dataList = mZeroHelper.getRecordList()
        dataList.forEach {
            resultList.add(it.toShowBean())
        }
        return resultList.toList()
    }

    fun getHasWithdrawSuccessCashCount(): Double {
        return mCashHelper.getHasWithdrawSuccessCashCount()
    }

    fun getHasWithdrawSuccessCashCount(itemIndex: Int): Double {
        return mCashHelper.getHasWithdrawSuccessCashCount(itemIndex)
    }

    fun updateRecordHasNotifyState(operationUUID: String) {
        return mCashHelper.updateRecordHasNotifyState(operationUUID)
    }

    fun saveNewWithdrawRecord(withdrawRecord: RecordCash) {
        return mCashHelper.saveNewWithdrawRecord(withdrawRecord)
    }


    fun getWithdrawRecordList(): List<RecordCash> {
        return mCashHelper.getWithdrawRecordList()
    }

    fun getOngoingRecordList(): List<RecordCash> {
        return mCashHelper.getOngoingRecordList()
    }

}





class CashRecordHelper() : BaseRecordHelper<RecordCash>() {
    override val mSpKey = SpUtil.KEY_RECORD_CASH
    override fun loadRecordsFromSp(): List<RecordCash> {
        return SpUtil.instance().getList<RecordCash>(mSpKey)
    }

    fun getHasWithdrawSuccessCashCount(): Double {
        var count = 0.0
        try {
            mRecordLocker.lock()

            for (record in mRecordList) {
                if (record.recordType == RECORD_CASH_WITHDRAW && record.withdrawState == TRANSACTION_STATE_SUCCESS) {
                    count += record.amountNum
                }
            }

            // extra withdraw count from zeroBuy
            count += ZeroManager.instance().getZeroHasWithdrawSuccessCashCount()
        } finally {
            mRecordLocker.unlock()
        }
        return count
    }

    fun getHasWithdrawSuccessCashCount(itemIndex: Int): Double {
        var count = 0.0
        try {
            mRecordLocker.lock()

            for (record in mRecordList) {
                if (record.withdrawItemIndex == itemIndex
                    && record.recordType == RECORD_CASH_WITHDRAW
                    && record.withdrawState == TRANSACTION_STATE_SUCCESS) {
                    count += record.amountNum
                }
            }
        } finally {
            mRecordLocker.unlock()
        }
        return count
    }

    fun getWithdrawRecord(operationUUID: String): RecordCash? {
        try {
            mRecordLocker.lock()
            mRecordList.forEachIndexed { index, record ->
                if (record.uuid == operationUUID) {
                    return record
                }
            }
        } finally {
            mRecordLocker.unlock()
        }
        return null
    }

    fun updateRecordHasNotifyState(operationUUID: String) {
        val recordBean: RecordCash? = getWithdrawRecord(operationUUID)
        recordBean?.let {
            it.hasShowResultDialog = true
            saveRecordList2Sp()
        }
    }

    fun saveNewWithdrawRecord(newRecord: RecordCash) {
        try {
            mRecordLocker.lock()
            mRecordList.add(newRecord)
            saveRecordList2Sp()
        } finally {
            mRecordLocker.unlock()
        }
    }


    fun getWithdrawRecordList(): List<RecordCash> {
        try {
            mRecordLocker.lock()
            val clonedList = mutableListOf<RecordCash>()
            mRecordList.forEach {
                if (it.recordType == RECORD_CASH_WITHDRAW) {
                    clonedList.add(it)
                }
            }
            return clonedList
        } finally {
            mRecordLocker.unlock()
        }
    }

    fun getOngoingRecordList(): List<RecordCash> {
        try {
            mRecordLocker.lock()
            val clonedList = mutableListOf<RecordCash>()
            mRecordList.forEach {
                if (it.recordType == RECORD_CASH_WITHDRAW && it.withdrawState == TRANSACTION_STATE_ONGOING) {
                    clonedList.add(it)
                }
            }
            return clonedList
        } finally {
            mRecordLocker.unlock()
        }
    }

}

class GoldRecordHelper() : BaseRecordHelper<RecordGold>() {
    override val mSpKey = SpUtil.KEY_RECORD_GOLD
    override fun loadRecordsFromSp(): List<RecordGold> {
        return SpUtil.instance().getList<RecordGold>(mSpKey)
    }
}

class ZeroRecordHelper() : BaseRecordHelper<RecordZero>() {
    override val mSpKey = SpUtil.KEY_RECORD_ZERO
    override fun loadRecordsFromSp(): List<RecordZero> {
        return SpUtil.instance().getList<RecordZero>(mSpKey)
    }
}


abstract class BaseRecordHelper<T: BaseRecord> {
    abstract val mSpKey: String
    private val mbgScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
    protected val mRecordLocker = ReentrantLock()
    protected val mRecordList: MutableList<T> by lazy { loadRecordsFromSp().toMutableList() }


    abstract fun loadRecordsFromSp() : List<T>


    fun getRecordList(): List<T> {
        return mRecordList.toList()
    }

    protected fun saveRecordList2Sp() {
        mbgScope.launch {
            try {
                mRecordLocker.lock()
                SpUtil.instance().putList(mSpKey, mRecordList)
            } finally {
                mRecordLocker.unlock()
            }
        }
    }

    fun addRecord(dataBean: T) {
        mbgScope.launch {
            try {
                mRecordLocker.lock()
                mRecordList.add(dataBean)
                saveRecordList2Sp()
            } finally {
                mRecordLocker.unlock()
            }

        }
    }

    fun updateRecord(updateBean: T) {
        mbgScope.launch {
            try {
                mRecordLocker.lock()
                mRecordList.forEachIndexed { index, data ->
                    if (data.uuid == updateBean.uuid) {
                        mRecordList.remove(data)
                        mRecordList.add(index, updateBean)
                        return@forEachIndexed
                    }
                }

                saveRecordList2Sp()
            } finally {
                mRecordLocker.unlock()
            }
        }
    }

}

