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

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.*;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.galaxy.dto.param.GalaxyNftPublishAndBuyResultQueryReqDto;
import com.liquidnet.service.galaxy.dto.param.GalaxyNftPublishAndBuyResultQueryRespDto;
import com.liquidnet.service.galaxy.dto.param.GalaxyNftTransferReqDto;
import com.liquidnet.service.galaxy.service.IGalaxyTradeService;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.GoblinQueueBizMongoDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinUserDigitalArtworkService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class GoblinUserDigitalArtworkServiceImpl implements IGoblinUserDigitalArtworkService {
    @Autowired
    private QueueUtils queueUtils;
    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private GoblinMongoUtils goblinMongoUtils;
    @Resource(name = "galaxyTradeServiceImpl")
    private IGalaxyTradeService galaxyTradeService;

    @Override
    public GoblinUserDigitalArtworkPageVo page(String uid, Integer pageNum, Integer pageSize) {
        GoblinUserDigitalArtworkPageVo pageVo = GoblinUserDigitalArtworkPageVo.getNew();
        long artworkNum = goblinRedisUtils.countUserDigitalArtwork(uid);
        if (artworkNum > 0) {
            PagedResult<GoblinUserDigitalArtworkListVo> listVoPagedResult = ObjectUtil.getGoblinUserDigitalArtworkListVoPagedResult();
            List<String> subArtworkIdList;
            if (artworkNum > 30 && pageNum * pageSize > 30) {// 查询Mongo
//                if ((long) pageNum * pageSize > artworkNum) pageNum = Math.toIntExact(artworkNum / pageSize);
                subArtworkIdList = goblinMongoUtils.getPageUserDigitalArtworkIds(uid, pageNum, pageSize);
//                if (CollectionUtils.isEmpty(subArtworkIdList)) {
//                    log.warn("#我的藏品列表:藏品IDS数据为空[uid={},artworkNum={}]", uid, artworkNum);
//                    return pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult).setSystime(LocalDateTime.now());
//                }
            } else {
                List<String> userDigitalArtworkIds = goblinRedisUtils.getUserDigitalArtworkIds(uid);
//                if (CollectionUtils.isEmpty(userDigitalArtworkIds)) {
                if (CollectionUtils.isEmpty(userDigitalArtworkIds) || ((pageNum - 1) * pageSize > (userDigitalArtworkIds.size() - 1))) {
                    log.warn("#我的藏品列表:藏品IDS缓存为空[uid={},artworkNum={}]", uid, artworkNum);
                    return pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult).setSystime(LocalDateTime.now());
                }

                int cacheSize = userDigitalArtworkIds.size(), cacheNum = cacheSize / pageSize;// 分几页
//                int fromIndex = Math.min(Math.min(cacheNum, pageNum - 1) * pageSize, cacheSize - 1);
                int fromIndex = (pageNum - 1) * pageSize;
                subArtworkIdList = userDigitalArtworkIds.subList(fromIndex, Math.min(fromIndex + pageSize, cacheSize));
            }
            if (CollectionUtils.isEmpty(subArtworkIdList)) {
                log.warn("#我的藏品列表:藏品IDS数据为空[uid={},artworkNum={}]", uid, artworkNum);
                return pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult).setSystime(LocalDateTime.now());
            }

            Map<String, Long> transferConfMap, transferConfFirstMap = null, transferConfAgainMap = null;

            List<GoblinUserDigitalArtworkListVo> list = ObjectUtil.getGoblinUserDigitalArtworkListVoArrayList();
            LocalDateTime now = LocalDateTime.now(), toCheckTime = now.minusSeconds(15);
            for (int i = 0, subSize = subArtworkIdList.size(); i < subSize; i++) {
                GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(subArtworkIdList.get(i));
                if (null == userDigitalArtworkVo || !userDigitalArtworkVo.getUid().equals(uid)) {
                    continue;
                }
                GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());

                GoblinUserDigitalArtworkListVo listVo = GoblinUserDigitalArtworkListVo.getNew().copy(userDigitalArtworkVo);
                listVo.setName(goodsSkuInfoVo.getName());
                listVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
                listVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
                listVo.setEdition(goodsSkuInfoVo.getSkuStock());
                listVo.setUnbox(goodsSkuInfoVo.getUnbox());
                listVo.setOpeningTime(goodsSkuInfoVo.getOpeningTime());
                listVo.setRouteType(goodsSkuInfoVo.getRouteType());

                // 非盲盒 && 生成中 && 创建时间判断
                if ("0".equals(listVo.getUnbox()) && 0 == listVo.getState() && listVo.getCreatedAt().isBefore(toCheckTime)) {// 15秒前创建的藏品，去主动核实发行交易状态
                    this.updateUserDigitalArtworkByChainTrade(userDigitalArtworkVo, listVo, goodsSkuInfoVo.getRouteType(), now);
                }
//                else if (1 == listVo.getState() && "1".equals(listVo.getUnbox())) {// 盲盒已开启的，直接展示开出的藏品封面
//                    GoblinNftOrderVo goblinNftOrder = goblinRedisUtils.getGoblinNftOrder(userDigitalArtworkVo.getOrderId());
//                    goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(goblinNftOrder.getBoxSkuId());
//                    listVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
//                }

                if (userDigitalArtworkVo.getSource() == 6) {
                    transferConfMap = CollectionUtils.isEmpty(transferConfAgainMap) ? transferConfAgainMap = goblinRedisUtils.getUserDigitalArtworkTransferConfMap(6) : transferConfAgainMap;
                } else {
                    transferConfMap = CollectionUtils.isEmpty(transferConfFirstMap) ? transferConfFirstMap = goblinRedisUtils.getUserDigitalArtworkTransferConfMap() : transferConfFirstMap;
                }
                if (transferConfMap.containsKey(goodsSkuInfoVo.getRouteType()) && StringUtils.isNotEmpty(userDigitalArtworkVo.getTradingAt())) {
                    long transferTimeLimit = transferConfMap.get(goodsSkuInfoVo.getRouteType());
                    listVo.setTransferAllowTime(DateUtil.Formatter.yyyyMMddHHmmss.parse(userDigitalArtworkVo.getTradingAt()).plusSeconds(transferTimeLimit));
                }

                list.add(listVo);
            }

            listVoPagedResult.setList(list).setTotal(artworkNum, pageSize);
            pageVo.setArtworkNum((int) artworkNum).setPagedResult(listVoPagedResult);
        }
        return pageVo;
    }

    @Override
    public List<GoblinUserDigitalArtworkTransferListVo> getArtworkListFromTransfer(String uid) {
        List<String> artworkIdsTransferList = goblinRedisUtils.getUserDigitalArtworkIdsTransfer(uid);
        if (CollectionUtils.isEmpty(artworkIdsTransferList)) return null;

        ArrayList<GoblinUserDigitalArtworkTransferListVo> listVos = ObjectUtil.getGoblinUserDigitalArtworkTransferListVos();
        Map<String, GoblinGoodsSkuInfoVo> tmpGoodsSkuInfoVoMap = ObjectUtil.getGoblinGoodsSkuInfoVoMap();
        Map<String, Long> transferConfMap, transferConfFirstMap = null, transferConfAgainMap = null;

        for (String artworkId : artworkIdsTransferList) {
            GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
            if (
                    null == userDigitalArtworkVo
                            || null == userDigitalArtworkVo.getTransferState()
                            || !userDigitalArtworkVo.getReceiverUid().equals(uid)
                            || GoblinStatusConst.TransferState.SUCCESS.name().equals(userDigitalArtworkVo.getTransferState())
                            || userDigitalArtworkVo.getTransferAt().plusDays(1).isBefore(LocalDateTime.now())
            ) {
                continue;
            }

            GoblinGoodsSkuInfoVo goodsSkuInfoVo = tmpGoodsSkuInfoVoMap.get(userDigitalArtworkVo.getSkuId());
            if (null == goodsSkuInfoVo) {
                if (null == (goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId())))
                    continue;

                tmpGoodsSkuInfoVoMap.put(userDigitalArtworkVo.getSkuId(), goodsSkuInfoVo);
            }

            GoblinUserDigitalArtworkTransferListVo listVo = GoblinUserDigitalArtworkTransferListVo.getNew().copy(userDigitalArtworkVo);
            listVo.setName(goodsSkuInfoVo.getName());
            listVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
            listVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
            listVo.setEdition(goodsSkuInfoVo.getSkuStock());
            listVo.setUnbox(goodsSkuInfoVo.getUnbox());
            listVo.setOpeningTime(goodsSkuInfoVo.getOpeningTime());
            listVo.setRouteType(goodsSkuInfoVo.getRouteType());

            if (null != userDigitalArtworkVo.getTransferAt()) {
                listVo.setTransferExpireTime(userDigitalArtworkVo.getTransferAt().plusDays(1));
            }

            listVos.add(listVo);
        }
        return listVos;
    }

    @Override
    public GoblinUserDigitalArtworkInfoVo info(String uid, String artworkId) {
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        /*if (null != userDigitalArtworkVo && userDigitalArtworkVo.getUid().equals(uid)) {
            GoblinUserDigitalArtworkInfoVo artworkInfoVo = GoblinUserDigitalArtworkInfoVo.getNew().copy(userDigitalArtworkVo);

            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());
            GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(goodsSkuInfoVo.getSpuId());
            GoblinNftOrderVo nftOrder = goblinRedisUtils.getGoblinNftOrder(userDigitalArtworkVo.getOrderId());
            if (null != nftOrder && StringUtils.isNotBlank(nftOrder.getBoxSkuId())) {
                artworkInfoVo.setSkuId(nftOrder.getSkuId());
            }

            artworkInfoVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
            artworkInfoVo.setName(goodsSkuInfoVo.getName());
            artworkInfoVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
            artworkInfoVo.setMaterialType(goodsSkuInfoVo.getMaterialType());
            artworkInfoVo.setMaterialUrl(goodsSkuInfoVo.getMaterialUrl());
            artworkInfoVo.setEdition(goodsSkuInfoVo.getSkuStock());
            artworkInfoVo.setAuthor(goodsInfoVo.getAuthor());
            artworkInfoVo.setPublisher(goodsInfoVo.getPublisher());
            artworkInfoVo.setDetails(goodsSkuInfoVo.getDetails());
            artworkInfoVo.setArUrlIos(goodsSkuInfoVo.getArUrlIos());
            artworkInfoVo.setArUrlAndroid(goodsSkuInfoVo.getArUrlAndroid());
//            artworkInfoVo.setGenerateTime(goodsSkuInfoVo.getDeclareAt());
            artworkInfoVo.setSkuWatchPic(goodsSkuInfoVo.getSkuWatchPic());

            return artworkInfoVo;
        }*/
        if (null != userDigitalArtworkVo && (uid.equals(userDigitalArtworkVo.getUid()) || uid.equals(userDigitalArtworkVo.getReceiverUid()))) {
            GoblinUserDigitalArtworkInfoVo artworkInfoVo = GoblinUserDigitalArtworkInfoVo.getNew().copy(userDigitalArtworkVo);

            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());
//            GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(goodsSkuInfoVo.getSpuId());
            GoblinNftOrderVo nftOrder = goblinRedisUtils.getGoblinNftOrder(userDigitalArtworkVo.getOrderId());
            if (null != nftOrder && StringUtils.isNotBlank(nftOrder.getBoxSkuId())) {
                artworkInfoVo.setSkuId(nftOrder.getSkuId());
            }
            artworkInfoVo.setCoverPic(goodsSkuInfoVo.getSkuPic());
            artworkInfoVo.setName(goodsSkuInfoVo.getName());
            artworkInfoVo.setSubtitle(goodsSkuInfoVo.getSubtitle());
//            artworkInfoVo.setAuthor(goodsInfoVo.getAuthor());
//            artworkInfoVo.setPublisher(goodsInfoVo.getPublisher());
            artworkInfoVo.setEdition(goodsSkuInfoVo.getSkuStock());
            artworkInfoVo.setSkuWatchPic(goodsSkuInfoVo.getSkuWatchPic());
            artworkInfoVo.setRouteType(goodsSkuInfoVo.getRouteType());

            String transferState = userDigitalArtworkVo.getTransferState();
            boolean transferFlg = StringUtils.isNotEmpty(transferState);
            if (transferFlg) {// 发生转赠
                artworkInfoVo.setTransferTime(userDigitalArtworkVo.getTransferAt());
                if (GoblinStatusConst.TransferState.WAITING.name().equals(transferState) && null != artworkInfoVo.getTransferTime()) {
                    artworkInfoVo.setTransferExpireTime(artworkInfoVo.getTransferTime().plusDays(1));
                }
                if (uid.equals(userDigitalArtworkVo.getReceiverUid())) {// 受赠人查取详情返回转赠人UID，用于前端查取转赠人身份信息使用
                    artworkInfoVo.setTransferUid(userDigitalArtworkVo.getUid());
                }
            }
            if ("0".equals(goodsSkuInfoVo.getUnbox()) && 1 == userDigitalArtworkVo.getState() && !transferFlg) {// 非盲盒 & 已上链 & 非转赠（转赠中、已转赠）
                artworkInfoVo.setMaterialType(goodsSkuInfoVo.getMaterialType());
                artworkInfoVo.setMaterialUrl(goodsSkuInfoVo.getMaterialUrl());
                artworkInfoVo.setDetails(goodsSkuInfoVo.getDetails());
                artworkInfoVo.setArUrlIos(goodsSkuInfoVo.getArUrlIos());
                artworkInfoVo.setArUrlAndroid(goodsSkuInfoVo.getArUrlAndroid());
                Map<String, Long> transferConfMap = goblinRedisUtils.getUserDigitalArtworkTransferConfMap(userDigitalArtworkVo.getSource());
                if (transferConfMap.containsKey(artworkInfoVo.getRouteType()) && StringUtils.isNotEmpty(userDigitalArtworkVo.getTradingAt())) {
                    long transferTimeLimit = transferConfMap.get(goodsSkuInfoVo.getRouteType());
                    artworkInfoVo.setTransferAllowTime(DateUtil.Formatter.yyyyMMddHHmmss.parse(userDigitalArtworkVo.getTradingAt()).plusSeconds(transferTimeLimit));
                }
                artworkInfoVo.setSystime(LocalDateTime.now());
            }
            return artworkInfoVo;
        }
        return null;
    }

    @Override
    public GoblinUserDigitalArtworkListVo unboxingForBuyOrExchange(String uid, GoblinUserDigitalArtworkVo userDigitalArtworkBoxVo) {
        LocalDateTime now = LocalDateTime.now();
        userDigitalArtworkBoxVo.setState(1);
        userDigitalArtworkBoxVo.setDelFlg("1");// 盲盒开启后直接删除
        userDigitalArtworkBoxVo.setOpeningAt(now);
        userDigitalArtworkBoxVo.setUpdatedAt(now);
        userDigitalArtworkBoxVo.setDeletedAt(now);

//        if (goblinMongoUtils.updateUserDigitalArtworkVoByUnboxing(userDigitalArtworkBoxVo)) {
//            String artworkId = IDGenerator.nextMilliId2();
        String artworkId = IDGenerator.nextSnowId();

        String orderId = userDigitalArtworkBoxVo.getOrderId();
        GoblinNftOrderVo orderVo = goblinRedisUtils.getGoblinNftOrder(orderId);
        GoblinGoodsSkuInfoVo unboxSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(orderVo.getBoxSkuId());

        GoblinUserDigitalArtworkListVo unboxDigitalArtworkListVo = GoblinUserDigitalArtworkListVo.getNew();
        unboxDigitalArtworkListVo.setArtworkId(artworkId);
        unboxDigitalArtworkListVo.setName(unboxSkuInfoVo.getName());
        unboxDigitalArtworkListVo.setSubtitle(unboxSkuInfoVo.getSubtitle());
        unboxDigitalArtworkListVo.setCoverPic(unboxSkuInfoVo.getSkuPic());
//            unboxDigitalArtworkListVo.setSource(userDigitalArtworkBoxVo.getSource());
//            unboxDigitalArtworkListVo.setState(0);
//            unboxDigitalArtworkListVo.setCreatedAt();
//            unboxDigitalArtworkListVo.setUnbox("0");
//            unboxDigitalArtworkListVo.setOpeningTime(now);

        String skuId = orderVo.getBoxSkuId(), spuId = orderVo.getSpuId();
//            Integer source = 1;
        Integer orderType = orderVo.getOrderType();
        Integer source = orderType == 1 ? 1 : (orderType == 2 ? 2 : (orderType == 3 ? 3 : (orderType == 4 ? 31 : 0)));
//            if (goblinRedisUtils.hasGenUserDigitalArtwork(uid, skuId, orderId)) {// 已生成
//                log.warn("#UNBOX_ARTWORK EXIST_ART[uid={},skuId={},orderId={},source={}]", uid, skuId, orderId, source);
//                return unboxDigitalArtworkListVo;
//            }
        userDigitalArtworkBoxVo.setHitArtworkId(artworkId);
//            goblinRedisUtils.setexUserDigitalArtworkVo(userDigitalArtworkBoxVo);

        GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(spuId);

        GoblinUserDigitalArtworkVo initUserDigitalArtworkVo = GoblinUserDigitalArtworkVo.getNew();
//            String artworkId = IDGenerator.nextMilliId2();
        initUserDigitalArtworkVo.setArtworkId(artworkId);
        initUserDigitalArtworkVo.setSkuId(skuId);
        initUserDigitalArtworkVo.setUid(uid);
        initUserDigitalArtworkVo.setOrderId(orderId);
        initUserDigitalArtworkVo.setSource(source);
        initUserDigitalArtworkVo.setState(0);
        initUserDigitalArtworkVo.setDelFlg("0");
        initUserDigitalArtworkVo.setCreatedAt(now);
        initUserDigitalArtworkVo.setAuthor(goodsInfoVo.getAuthor());
        initUserDigitalArtworkVo.setPublisher(goodsInfoVo.getPublisher());

//            // Mongo记录VO
//            goblinMongoUtils.insertUserDigitalArtworkVo(initUserDigitalArtworkVo);
        // Redis更新VO
        goblinRedisUtils.setexUserDigitalArtworkVo(userDigitalArtworkBoxVo, 48 * 3600);
        // Redis记录VO
        goblinRedisUtils.setUserDigitalArtworkVo(initUserDigitalArtworkVo);
        // Redis更新藏品ID列表
        goblinRedisUtils.addUserDigitalArtworkIdsForUnbox(uid, artworkId, userDigitalArtworkBoxVo.getArtworkId());
        {// Redis更新藏品订单关联artworkId
            orderVo.setArtworkId(artworkId);
            goblinRedisUtils.setGoblinNftOrder(orderVo);
            // Mongo同步更新藏品订单
            MdbMessage mdbMessage = MdbMessage.getNew();
            mdbMessage.setCollect(GoblinNftOrderVo.class.getSimpleName());
            mdbMessage.setColumn("orderId");
            mdbMessage.setBizId(orderVo.getOrderId());
            mdbMessage.setPrefix(GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_INFO);
            mdbMessage.setOpType(2);
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_NFT_MONGO.getKey(), mdbMessage.toJson());
        }

        if ("0".equals(unboxSkuInfoVo.getUnbox())) {// 非盲盒，NFT发行购买
            ObjectNode bizNftBuyNode = JsonUtils.OM().createObjectNode().put("nftOrderPayId", orderId).put("routerType", unboxSkuInfoVo.getRouteType())
                    .put("skuId", skuId).put("userId", uid).put("buyTimestamp", DateUtil.Formatter.yyyyMMddHHmmss.format(now));
            queueUtils.sendMsgByRedis(MQConst.GalaxyQueue.JSON_NFT_PUBLISH_AND_BUY.getKey(), bizNftBuyNode.toString());
        }

        // Mysql持久化
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.insert"));
        LinkedList<Object[]> initUserDigitalArtworkObjs = CollectionUtil.linkedListObjectArr();
        initUserDigitalArtworkObjs.add(new Object[]{initUserDigitalArtworkVo.getArtworkId(), skuId, uid, orderId, source, initUserDigitalArtworkVo.getState(), now});
        toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.update_for_unboxing"));
        LinkedList<Object[]> updateBoxArtworkObjs = CollectionUtil.linkedListObjectArr();
        updateBoxArtworkObjs.add(new Object[]{now, now, now, userDigitalArtworkBoxVo.getArtworkId()});
        toMqSqls.add(SqlMapping.get("goblin_nft_order.update_artwork"));
        LinkedList<Object[]> updateNftOrderObjs = CollectionUtil.linkedListObjectArr();
        updateNftOrderObjs.add(new Object[]{artworkId, orderId});
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(), SqlMapping.gets(toMqSqls, initUserDigitalArtworkObjs, updateBoxArtworkObjs, updateNftOrderObjs));

        // Mongo同步更新
        GoblinQueueBizMongoDto goblinQueueBizMongoDto = GoblinQueueBizMongoDto.getNew();
        goblinQueueBizMongoDto.setCollect(GoblinUserDigitalArtworkVo.class.getSimpleName());
        goblinQueueBizMongoDto.setColumn("artworkId");
        goblinQueueBizMongoDto.setBizId(userDigitalArtworkBoxVo.getArtworkId());
        goblinQueueBizMongoDto.setPrefix(GoblinRedisConst.USER_DIGITAL_ARTWORK);
        goblinQueueBizMongoDto.setOpType(2);
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_NFT_MONGO.getKey(), goblinQueueBizMongoDto.toJson());

        // Mongo记录VO
        goblinMongoUtils.insertUserDigitalArtworkVo(initUserDigitalArtworkVo);

        return unboxDigitalArtworkListVo;
//        }
//        return null;
    }

    @Override
    public boolean accept(String uid, GoblinUserDigitalArtworkVo userDigitalArtworkVo) {
        LocalDateTime now = LocalDateTime.now();
        userDigitalArtworkVo.setState(0);
        userDigitalArtworkVo.setOpeningAt(now);
        userDigitalArtworkVo.setUpdatedAt(now);

//        if (goblinMongoUtils.updateUserDigitalArtworkVoByAccept(userDigitalArtworkVo)) {
        // Redis更新VO
        goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo);

        String skuId = userDigitalArtworkVo.getSkuId();
        GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(skuId);

        if ("0".equals(goodsSkuInfoVo.getUnbox())) {// 非盲盒，NFT发行购买
            ObjectNode bizNftBuyNode = JsonUtils.OM().createObjectNode().put("nftOrderPayId", userDigitalArtworkVo.getOrderId()).put("routerType", goodsSkuInfoVo.getRouteType())
                    .put("skuId", skuId).put("userId", uid).put("buyTimestamp", DateUtil.Formatter.yyyyMMddHHmmss.format(now));
            queueUtils.sendMsgByRedis(MQConst.GalaxyQueue.JSON_NFT_PUBLISH_AND_BUY.getKey(), bizNftBuyNode.toString());
        }

        // Mysql持久化
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.update_for_accept"));
        LinkedList<Object[]> updateUserArtworkObjs = CollectionUtil.linkedListObjectArr();
        updateUserArtworkObjs.add(new Object[]{now, now, userDigitalArtworkVo.getArtworkId()});
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(), SqlMapping.gets(toMqSqls, updateUserArtworkObjs));

        // Mongo同步更新
        GoblinQueueBizMongoDto goblinQueueBizMongoDto = GoblinQueueBizMongoDto.getNew();
        goblinQueueBizMongoDto.setCollect(GoblinUserDigitalArtworkVo.class.getSimpleName());
        goblinQueueBizMongoDto.setColumn("artworkId");
        goblinQueueBizMongoDto.setBizId(userDigitalArtworkVo.getArtworkId());
        goblinQueueBizMongoDto.setPrefix(GoblinRedisConst.USER_DIGITAL_ARTWORK);
        goblinQueueBizMongoDto.setOpType(2);
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_NFT_MONGO.getKey(), goblinQueueBizMongoDto.toJson());

        return true;
//        }
//        return false;
    }

    @Override
    public boolean transfer(GoblinUserDigitalArtworkVo userDigitalArtworkVo, String routerType, String[] receiverArr) {
        LocalDateTime currentDateTime = LocalDateTime.now();
        userDigitalArtworkVo.setTransferAt(currentDateTime);
        userDigitalArtworkVo.setUpdatedAt(currentDateTime);
        userDigitalArtworkVo.setReceiverUid(receiverArr[0]);
        userDigitalArtworkVo.setTransferOrderId(IDGenerator.nextSnowId());
        userDigitalArtworkVo.setTransferState(GoblinStatusConst.TransferState.WAITING.name());
        userDigitalArtworkVo.setReceiverUser(SensitizeUtil.custom(receiverArr[1], 0, 1) + String.format(" (%s)", SensitizeUtil.custom(receiverArr[2], 3, 4)));
        if (goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo)) {
            // 受赠人受赠藏品列表缓存更新
            goblinRedisUtils.addUserDigitalArtworkIdsTransfer(userDigitalArtworkVo.getReceiverUid(), userDigitalArtworkVo.getArtworkId());

            // Mongo同步更新
            GoblinQueueBizMongoDto goblinQueueBizMongoDto = GoblinQueueBizMongoDto.getNew();
            goblinQueueBizMongoDto.setCollect(GoblinUserDigitalArtworkVo.class.getSimpleName());
            goblinQueueBizMongoDto.setColumn("artworkId");
            goblinQueueBizMongoDto.setBizId(userDigitalArtworkVo.getArtworkId());
            goblinQueueBizMongoDto.setPrefix(GoblinRedisConst.USER_DIGITAL_ARTWORK);
            goblinQueueBizMongoDto.setOpType(2);
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_NFT_MONGO.getKey(), goblinQueueBizMongoDto.toJson());

            // Mysql持久化
            LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
            toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.up_transfer"));
            LinkedList<Object[]> updateUserDigitalArtworkObjs = CollectionUtil.linkedListObjectArr();
            updateUserDigitalArtworkObjs.add(new Object[]{userDigitalArtworkVo.getReceiverUid(),
                    userDigitalArtworkVo.getTransferOrderId(), userDigitalArtworkVo.getTransferState(), userDigitalArtworkVo.getUpdatedAt(), userDigitalArtworkVo.getArtworkId()
            });
            toMqSqls.add(SqlMapping.get("goblin_nft_transfer_order.insert"));// 藏品订单记录
            LinkedList<Object[]> initNftTransferOrderObjs = CollectionUtil.linkedListObjectArr();
            initNftTransferOrderObjs.add(new Object[]{userDigitalArtworkVo.getTransferOrderId(),
                    userDigitalArtworkVo.getArtworkId(), userDigitalArtworkVo.getUid(), userDigitalArtworkVo.getReceiverUid(), currentDateTime
            });
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(), SqlMapping.gets(toMqSqls, updateUserDigitalArtworkObjs, initNftTransferOrderObjs));
            return true;
        }
        return false;
    }

    @Override
    public boolean transferConfirmReceive(String artworkId) {
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (!GoblinStatusConst.TransferState.WAITING.name().equals(userDigitalArtworkVo.getTransferState())) {
            return false;// 藏品已领取或已退还
        }
        LocalDateTime currentDateTime = LocalDateTime.now();
        userDigitalArtworkVo.setUpdatedAt(currentDateTime);
        userDigitalArtworkVo.setTransferState(GoblinStatusConst.TransferState.PENDING.name());
        if (goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo)) {
            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());

            GalaxyNftTransferReqDto galaxyNftTransferReqDto = GalaxyNftTransferReqDto.getNew();
            galaxyNftTransferReqDto.setRouterType(goodsSkuInfoVo.getRouteType());
            galaxyNftTransferReqDto.setNftId(userDigitalArtworkVo.getNftId());
            galaxyNftTransferReqDto.setUserId(userDigitalArtworkVo.getUid());
            galaxyNftTransferReqDto.setReceiveUserId(userDigitalArtworkVo.getReceiverUid());
            galaxyNftTransferReqDto.setTransOrderId(userDigitalArtworkVo.getTransferOrderId());
            galaxyNftTransferReqDto.setReqTimestamp(DateUtil.Formatter.yyyyMMddHHmmss.format(currentDateTime));
            queueUtils.sendMsgByRedis(MQConst.GalaxyQueue.JSON_NFT_TRANSFER.getKey(), JsonUtils.toJson(galaxyNftTransferReqDto));
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_ARTWORK_TRANS_QUERY.getKey(), userDigitalArtworkVo.getArtworkId().concat(",").concat(String.valueOf(currentDateTime)));

            // Mongo同步更新
            MdbMessage mdbMessage = MdbMessage.getNew();
            mdbMessage.setCollect(GoblinUserDigitalArtworkVo.class.getSimpleName());
            mdbMessage.setColumn("artworkId");
            mdbMessage.setBizId(userDigitalArtworkVo.getArtworkId());
            mdbMessage.setPrefix(GoblinRedisConst.USER_DIGITAL_ARTWORK);
            mdbMessage.setOpType(2);
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.BIZ_NFT_MONGO.getKey(), mdbMessage.toJson());

            // Mysql持久化
            LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
            toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.up_transfer_receive"));
            LinkedList<Object[]> updateUserDigitalArtworkObjs = CollectionUtil.linkedListObjectArr();
            updateUserDigitalArtworkObjs.add(new Object[]{
                    userDigitalArtworkVo.getTransferState(), userDigitalArtworkVo.getUpdatedAt(), userDigitalArtworkVo.getArtworkId()
            });
            toMqSqls.add(SqlMapping.get("goblin_nft_transfer_order.up_transfer_confirm"));// 藏品订单记录更新
            LinkedList<Object[]> updateNftTransferOrderObjs = CollectionUtil.linkedListObjectArr();
            updateNftTransferOrderObjs.add(new Object[]{1, currentDateTime, userDigitalArtworkVo.getTransferOrderId()});
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(), SqlMapping.gets(toMqSqls, updateUserDigitalArtworkObjs, updateNftTransferOrderObjs));
            return true;
        }
        return false;
    }

    @Override
    public boolean transferConfirmReturn(String artworkId) {
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (!GoblinStatusConst.TransferState.WAITING.name().equals(userDigitalArtworkVo.getTransferState())) {
            return false;// 藏品已领取或已退还
        }
        String receiverUid = userDigitalArtworkVo.getReceiverUid(), transferOrderId = userDigitalArtworkVo.getTransferOrderId();
        if (goblinRedisUtils.rmvUserDigitalArtworkIdsTransfer(receiverUid, artworkId)) {
            LocalDateTime currentDateTime = LocalDateTime.now();
            // 转赠人藏品恢复
            userDigitalArtworkVo.setUpdatedAt(currentDateTime);
            userDigitalArtworkVo.setTransferOrderId(null);
            userDigitalArtworkVo.setTransferState(null);
            userDigitalArtworkVo.setReceiverUid(null);
            userDigitalArtworkVo.setReceiverUser(null);
            userDigitalArtworkVo.setTransferAt(null);
            goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo);

            // Mongo藏品数据更新
            goblinMongoUtils.updateUserDigitalArtworkVoByTransReturn(artworkId, currentDateTime);

            // Mysql转赠订单更新
            LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
            toMqSqls.add(SqlMapping.get("goblin_user_digital_artwork.up_transfer_return"));
            LinkedList<Object[]> updateUserDigitalArtworkObjs = CollectionUtil.linkedListObjectArr();
            updateUserDigitalArtworkObjs.add(new Object[]{userDigitalArtworkVo.getUpdatedAt(), userDigitalArtworkVo.getArtworkId()});
            toMqSqls.add(SqlMapping.get("goblin_nft_transfer_order.up_transfer_confirm"));// 藏品订单记录更新
            LinkedList<Object[]> updateNftTransferOrderObjs = CollectionUtil.linkedListObjectArr();
            updateNftTransferOrderObjs.add(new Object[]{2, currentDateTime, transferOrderId});
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(), SqlMapping.gets(toMqSqls, updateUserDigitalArtworkObjs, updateNftTransferOrderObjs));
            return true;
        }
        return false;
    }

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

    private void updateUserDigitalArtworkByChainTrade(GoblinUserDigitalArtworkVo userDigitalArtworkVo, GoblinUserDigitalArtworkListVo listVo,
                                                      String routerType, LocalDateTime now) {
        try {
            GalaxyNftPublishAndBuyResultQueryReqDto nftTradeQueryReqDto = GalaxyNftPublishAndBuyResultQueryReqDto.getNew();
            nftTradeQueryReqDto.setUserId(userDigitalArtworkVo.getUid());
            nftTradeQueryReqDto.setNftOrderPayId(userDigitalArtworkVo.getOrderId());
            nftTradeQueryReqDto.setRouterType(routerType);
            ResponseDto<GalaxyNftPublishAndBuyResultQueryRespDto> nftTradeQueryRespDto = galaxyTradeService.nftPublishAndBuyResultQuery(nftTradeQueryReqDto);
            if (nftTradeQueryRespDto.isSuccess()) {
                GalaxyNftPublishAndBuyResultQueryRespDto nftTradeQueryRespDtoData = nftTradeQueryRespDto.getData();
                String nftId = nftTradeQueryRespDtoData.getNftId();

                listVo.setState(1);
                listVo.setEditionSn(Integer.valueOf(nftId.substring(nftId.indexOf("_") + 1)));

                userDigitalArtworkVo.setEditionSn(listVo.getEditionSn());
                userDigitalArtworkVo.setNftId(nftId);
                userDigitalArtworkVo.setReleaseAt(nftTradeQueryRespDtoData.getNftPublishChainTimestamp());
                userDigitalArtworkVo.setReleaseTxhash(nftTradeQueryRespDtoData.getNftPublishTradeHash());
                userDigitalArtworkVo.setTradingAt(nftTradeQueryRespDtoData.getNftBuyChainTimestamp());
                userDigitalArtworkVo.setTradingTxhash(nftTradeQueryRespDtoData.getNftBuyTradeHash());
                userDigitalArtworkVo.setState(1);
                userDigitalArtworkVo.setUpdatedAt(now);

                goblinRedisUtils.setUserDigitalArtworkVo(userDigitalArtworkVo);
                goblinMongoUtils.updateUserDigitalArtworkVoByChainTrade(userDigitalArtworkVo);

                queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey(),
                        SqlMapping.get("goblin_user_digital_artwork.update_for_chain",
                                userDigitalArtworkVo.getEditionSn(), userDigitalArtworkVo.getNftId(), userDigitalArtworkVo.getReleaseTxhash(),
                                userDigitalArtworkVo.getReleaseAt(), userDigitalArtworkVo.getTradingTxhash(), userDigitalArtworkVo.getTradingAt(),
                                userDigitalArtworkVo.getState(), userDigitalArtworkVo.getUpdatedAt(), userDigitalArtworkVo.getArtworkId())
                );
            }
        } catch (Exception e) {
            log.error("Ex.我的藏品列表:藏品上链结果查询处理失败[uid={},orderId={}]", userDigitalArtworkVo.getUid(), userDigitalArtworkVo.getOrderId(), e);
        }
    }
}
