package com.liquidnet.service.platform.service.impl.goblin;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.common.cache.redis.util.AbstractRedisUtil;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.GoblinUserDigitalArtworkVo;
import com.liquidnet.service.goblin.entity.GoblinNftTransferOrder;
import com.liquidnet.service.goblin.entity.GoblinUserDigitalArtwork;
import com.liquidnet.service.goblin.mapper.GoblinNftTransferOrderMapper;
import com.liquidnet.service.goblin.mapper.GoblinUserDigitalArtworkMapper;
import com.liquidnet.service.platform.utils.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class PlatformGoblinNftTransferOrderService extends ServiceImpl<GoblinNftTransferOrderMapper, GoblinNftTransferOrder> {
    @Autowired
    private GoblinUserDigitalArtworkMapper goblinUserDigitalArtworkMapper;
    @Autowired
    private RedisDataSourceUtil redisDataSourceUtil;
    @Autowired
    private MongoTemplate mongoTemplate;

    public int processForTransferExpire(List<GoblinNftTransferOrder> list) {
        AbstractRedisUtil redisGoblinUtil = redisDataSourceUtil.getRedisGoblinUtil();
        ArrayList<String> updateUserDigitalArtworkIdList = CollectionUtil.arrayListString();
        ArrayList<GoblinNftTransferOrder> updateNftTransferOrderList = ObjectUtil.getGoblinNftTransferOrderArrayList();

        int numSucc = 0;
        LocalDateTime currentDateTime = LocalDateTime.now();
        for (int i = 0, listSize = CollectionUtils.isEmpty(list) ? -1 : list.size(); i < listSize; i++) {
            GoblinNftTransferOrder nftTransferOrder = list.get(i);

            String artworkId = nftTransferOrder.getArtworkId();
            if (this.lockUserDigitalArtworkVoOperate(artworkId)) {
                GoblinUserDigitalArtworkVo rdsVo = (GoblinUserDigitalArtworkVo) redisGoblinUtil.get(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat(artworkId));
                if (null != rdsVo && GoblinStatusConst.TransferState.WAITING.name().equals(rdsVo.getTransferState())) {
                    // 受赠人受赠藏品列表缓存更新
                    this.rmvUserDigitalArtworkIdsTransfer(rdsVo.getReceiverUid(), artworkId);
                    // 转赠人藏品恢复
                    rdsVo.setTransferOrderId(null);
                    rdsVo.setTransferState(null);
                    rdsVo.setReceiverUid(null);
                    rdsVo.setReceiverUser(null);//
                    rdsVo.setUpdatedAt(currentDateTime);
                    redisGoblinUtil.set(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat(artworkId), rdsVo);

                    nftTransferOrder.setState(3);
                    nftTransferOrder.setUpdatedAt(currentDateTime);
                    updateNftTransferOrderList.add(nftTransferOrder);
                    updateUserDigitalArtworkIdList.add(artworkId);

                    numSucc++;
                }

                this.unlockUserDigitalArtworkVoOperate(artworkId);
            }

        }
        if (numSucc > 0) {// 更新Mysql、Mongo
            this.updateBatchById(updateNftTransferOrderList, updateNftTransferOrderList.size());
            GoblinUserDigitalArtwork updateUserDigitalArtwork = new GoblinUserDigitalArtwork();
            updateUserDigitalArtwork.setTransferOrderId(null);
            updateUserDigitalArtwork.setTransferState(null);
            updateUserDigitalArtwork.setReceiverUid(null);
            updateUserDigitalArtwork.setUpdatedAt(currentDateTime);
            LambdaUpdateWrapper<GoblinUserDigitalArtwork> userDigitalArtworkLambdaUpdateWrapper = Wrappers.lambdaUpdate(GoblinUserDigitalArtwork.class)
                            .in(GoblinUserDigitalArtwork::getArtworkId, updateUserDigitalArtworkIdList)
                            .eq(GoblinUserDigitalArtwork::getTransferState, GoblinStatusConst.TransferState.WAITING.name());
            goblinUserDigitalArtworkMapper.update(updateUserDigitalArtwork, userDigitalArtworkLambdaUpdateWrapper);

            Query queryMongo = Query.query(
                    Criteria.where("artworkId").in(updateUserDigitalArtworkIdList).and("transferState").is(GoblinStatusConst.TransferState.WAITING.name())
            );
            Update updateMongo = Update.update("updatedAt", currentDateTime).unset("transferOrderId").unset("transferState")
                    .unset("receiverUid").unset("receiverUser").unset("transferAt");
            mongoTemplate.updateMulti(queryMongo, updateMongo, GoblinUserDigitalArtworkVo.class.getSimpleName());
        }
        return numSucc;
    }

    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */

    /**
     * 锁定藏品操作
     */
    private boolean lockUserDigitalArtworkVoOperate(String artworkId) {
        String lk = GoblinRedisConst.USER_DIGITAL_ARTWORK.concat("lk").concat(artworkId);
        AbstractRedisUtil redisUtil = redisDataSourceUtil.getRedisGoblinUtil();
        if (redisUtil.incr(lk, 1) > 1) {
            return false;
        }
        redisUtil.expireSet(lk, 30);
        return true;
    }

    /**
     * 解锁藏品操作
     */
    private void unlockUserDigitalArtworkVoOperate(String artworkId) {
        redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat("lk").concat(artworkId));
    }

    /**
     * 获取用户受赠藏品ID集合
     */
    public List<String> getUserDigitalArtworkIdsTransfer(String uid) {
        return (List<String>) redisDataSourceUtil.getRedisGoblinUtil().get(GoblinRedisConst.USER_DIGITAL_ARTWORK_IDS_TRANSFER.concat(uid));
    }

    private boolean rmvUserDigitalArtworkIdsTransfer(String uid, String artworkId) {
        List<String> ids = this.getUserDigitalArtworkIdsTransfer(uid);
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        } else {
            ids.remove(artworkId);
            if (CollectionUtils.isEmpty(ids)) {
                redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.USER_DIGITAL_ARTWORK_IDS_TRANSFER.concat(uid));
            } else {
                redisDataSourceUtil.getRedisGoblinUtil().set(GoblinRedisConst.USER_DIGITAL_ARTWORK_IDS_TRANSFER.concat(uid), ids);
            }
            return true;
        }
    }
    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */
    /* ------------------------------------------------------------------------------------ */
}
