package com.liquidnet.service.consumer.kylin.receiver;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.GoblinQueueBizArtworkGenDto;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUserDigitalArtworkVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.core.StreamOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

@Slf4j
@Component
public class ConsumerGoblinBizArtworkGenRdsReceiver extends AbstractBizRedisReceiver {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MongoTemplate mongoTemplate;

    private static final String SQL_INSERT_ARTWORK = "INSERT INTO goblin_user_digital_artwork (artwork_id, sku_id, uid, order_id, source, state, created_at)VALUES(?,?,?,?,?,?,?)";

    @Override
    protected String getRedisStreamKey() {
        return MQConst.GoblinQueue.BIZ_ARTWORK_GEN.getKey();
    }

    @Override
    protected String getRedisStreamGroup() {
        return MQConst.GoblinQueue.BIZ_ARTWORK_GEN.getGroup();
    }

    @Override
    protected boolean consumerMessageHandler(String msg) {
        boolean aBoolean = false;
        try {
            GoblinQueueBizArtworkGenDto fromJsonObj = JsonUtils.fromJson(msg, GoblinQueueBizArtworkGenDto.class);
            if (fromJsonObj == null) {
                log.warn("CONSUMER MSG NULL_DTO ==> [{}]:{}", this.getRedisStreamKey(), msg);
                aBoolean = true;
            } else {
                aBoolean = this.bizArtworkGenProcessing(fromJsonObj);
            }
        } catch (Exception e) {
            log.error("CONSUMER MSG EX_HANDLE ==> [{}]:{}", this.getRedisStreamKey(), msg, e);
        } finally {
            if (!aBoolean) {
                HashMap<String, String> map = CollectionUtil.mapStringString();
                map.put("message", msg);
                stringRedisTemplate.opsForStream().add(StreamRecords.mapBacked(map).withStreamKey(this.getRedisStreamKey()));
            }
        }
        return aBoolean;
    }

    private boolean bizArtworkGenProcessing(GoblinQueueBizArtworkGenDto dto) {
        String uid = dto.getUid(), skuId = dto.getSkuId(), orderId = dto.getOrderId(), fromArtworkId = dto.getFromArtId();
        Integer source = dto.getSource();

        GoblinGoodsSkuInfoVo goodsSkuInfoVo = this.getGoodsSkuInfoVoFromRdb(skuId);
        if (null == goodsSkuInfoVo || !"0".equals(goodsSkuInfoVo.getDelFlg())) {
            log.warn("#CONSUMER MSG NULL_SKU[{}]:[uid={},skuId={},orderId={},source={},fromArtworkId={}]", this.getRedisStreamKey(), uid, skuId, orderId, source, fromArtworkId);
            return true;
        }

        // 判断是否已生成
        String genMarkerKey = GoblinRedisConst.USER_DIGITAL_ARTWORK_GENMARK.concat(uid).concat(skuId).concat(orderId);
        if (this.hasUserDigitalArtworkVoFromRdb(genMarkerKey)) {// 已生成
            log.warn("#CONSUMER MSG EXIST_ART[{}]:[uid={},skuId={},orderId={},source={},fromArtworkId={}]", this.getRedisStreamKey(),
                    uid, skuId, orderId, source, fromArtworkId);
            return true;
        }
//            GoblinDigitalArtworkVo existDigitalArtworkVo = this.getDigitalArtworkVoFromMdb(uid, skuId, orderId);
//            if (null != existDigitalArtworkVo) {// 已生成
//                log.warn("#CONSUMER MSG EXIST_ART[{}]:[uid={},skuId={},orderId={},source={}]", this.getRedisStreamKey(),
//                        uid, skuId, orderId, source);
//                return true;
//            }

        GoblinGoodsInfoVo goodsInfoVo = this.getGoodsInfoVoFromRdb(goodsSkuInfoVo.getSpuId());

        LocalDateTime now = LocalDateTime.now();

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

        // Mongo记录VO
        mongoTemplate.insert(digitalArtworkVo, GoblinUserDigitalArtworkVo.class.getSimpleName());
        boolean fromBoxArtworkFlg = StringUtils.isNotEmpty(fromArtworkId);
        if (fromBoxArtworkFlg) {// 更新盲盒藏品数据
            GoblinUserDigitalArtworkVo userDigitalArtworkVo = this.getUserDigitalArtworkVoFromRdb(fromArtworkId);
            if (null != userDigitalArtworkVo) {
                mongoTemplate.getCollection(GoblinUserDigitalArtworkVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("artworkId").is(fromArtworkId).and("state").ne(1)).getQueryObject(),
                        Update.update("state", userDigitalArtworkVo.getState())
                                .set("delFlg", userDigitalArtworkVo.getDelFlg())
                                .set("openingAt", userDigitalArtworkVo.getOpeningAt())
                                .set("updatedAt", userDigitalArtworkVo.getUpdatedAt())
                                .set("deletedAt", userDigitalArtworkVo.getDeletedAt())
                                .getUpdateObject()
                );
            }
        } else {
            redisUtil.incr(GoblinRedisConst.USER_DIGITAL_ARTWORK_CT.concat(uid), 1);
        }
        // Redis记录VO
        redisUtil.set(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat(digitalArtworkVo.getArtworkId()), digitalArtworkVo);
        // Redis更新藏品ID列表
        this.addGoblinUserDigitalArtworkIds(uid, artworkId);
        // Redis生成标记（缓存三天），用于上面的生成检查
        redisUtil.set(genMarkerKey, 1, 259200);

        StreamOperations<String, Object, Object> streamOperations = stringRedisTemplate.opsForStream();
        // Mysql持久化
        HashMap<String, String> sqlArtworkMap = CollectionUtil.mapStringString();
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        toMqSqls.add(SQL_INSERT_ARTWORK);
        LinkedList<Object[]> initArtworkObjs = CollectionUtil.linkedListObjectArr();
        initArtworkObjs.add(new Object[]{digitalArtworkVo.getArtworkId(), skuId, uid, orderId, source, digitalArtworkVo.getState(), now});
        sqlArtworkMap.put(MQConst.QUEUE_MESSAGE_KEY, SqlMapping.gets(toMqSqls, initArtworkObjs));
        streamOperations.add(StreamRecords.mapBacked(sqlArtworkMap).withStreamKey(MQConst.GoblinQueue.SQL_ARTWORK_GEN.getKey()));
        // NFT发行购买
        HashMap<String, String> bizNftBuyMap = CollectionUtil.mapStringString();
        ObjectNode bizNftBuyNode = JsonUtils.OM().createObjectNode();
        bizNftBuyNode.put("nftOrderPayId", orderId).put("routerType", "zxinchain")
                .put("skuId", skuId).put("userId", uid).put("buyTimestamp", DateUtil.Formatter.yyyyMMddHHmmss.format(now));
        bizNftBuyMap.put(MQConst.QUEUE_MESSAGE_KEY, bizNftBuyNode.toString());
        RecordId add = streamOperations.add(StreamRecords.mapBacked(bizNftBuyMap).withStreamKey(MQConst.GalaxyQueue.JSON_NFT_PUBLISH_AND_BUY.getKey()));
        log.info("CONSUMER MSG GEN_ART_TQ[{},message={}]", JsonUtils.toJson(add), bizNftBuyMap);

        return true;
    }


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

//    public void setDigitalArtworkVo(GoblinDigitalArtworkVo vo) {
//        mongoTemplate.insert(vo, GoblinDigitalArtworkVo.class.getSimpleName());
//        redisUtil.set(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat(vo.getArtworkId()), vo);
//
//        LinkedList<Object[]> paramsList = CollectionUtil.linkedListObjectArr();
//        paramsList.add(new Object[]{vo.getArtworkId(), vo.getSkuId(), vo.getUid(), vo.getOrderId(), vo.getSource(), vo.getState(), vo.getCreatedAt()});
//        this.baseDao.batchSql(SQL_INSERT_ARTWORK, paramsList);
//    }
//
//    public void sendMsgByRedisToQueue(String streamKey, String jsonMsg) {
//        HashMap<String, String> map = CollectionUtil.mapStringString();
//        map.put("message", jsonMsg);
//        stringRedisTemplate.opsForStream().add(StreamRecords.mapBacked(map).withStreamKey(streamKey));
//    }

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


    public List<String> getUserDigitalArtworkIdsFromRdb(String uid) {
        return (List<String>) redisUtil.get(GoblinRedisConst.USER_DIGITAL_ARTWORK_IDS.concat(uid));
    }

    /**
     * 缓存并更新用户藏品ID集合
     */
    public boolean addGoblinUserDigitalArtworkIds(String uid, String artworkId) {
        List<String> ids = this.getUserDigitalArtworkIdsFromRdb(uid);
        if (CollectionUtils.isEmpty(ids)) {
            ids = CollectionUtil.arrayListString();
            ids.add(artworkId);
        } else {
            ids.add(0, artworkId);
            int size = ids.size();
            if (size > 30) ids.remove(size - 1);
        }
        return redisUtil.set(GoblinRedisConst.USER_DIGITAL_ARTWORK_IDS.concat(uid), ids);
    }

    public GoblinGoodsSkuInfoVo getGoodsSkuInfoVoFromRdb(String skuId) {
        String rk = GoblinRedisConst.BASIC_GOODS_SKU.concat(skuId);
        GoblinGoodsSkuInfoVo vo = (GoblinGoodsSkuInfoVo) redisUtil.get(rk);
        if (null == vo && null != (vo = this.getGoodsSkuInfoVoFromMdb(skuId))) {
            redisUtil.set(rk, vo);
        }
        return vo;
    }

    public GoblinGoodsInfoVo getGoodsInfoVoFromRdb(String spuId) {
        String rk = GoblinRedisConst.BASIC_GOODS.concat(spuId);
        GoblinGoodsInfoVo vo = (GoblinGoodsInfoVo) redisUtil.get(rk);
        if (null == vo && null != (vo = this.getGoodsInfoVoFromMdb(spuId))) {
            redisUtil.set(rk, vo);
        }
        return vo;
    }

    public GoblinUserDigitalArtworkVo getUserDigitalArtworkVoFromRdb(String artworkId) {
        return (GoblinUserDigitalArtworkVo) redisUtil.get(GoblinRedisConst.USER_DIGITAL_ARTWORK.concat(artworkId));
    }

    public boolean hasUserDigitalArtworkVoFromRdb(String genMarkerKey) {
        return redisUtil.hasKey(genMarkerKey);
    }

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

    public GoblinGoodsSkuInfoVo getGoodsSkuInfoVoFromMdb(String skuId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId)),
                GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    public GoblinGoodsInfoVo getGoodsInfoVoFromMdb(String spuId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId)),
                GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
    }

//    public GoblinDigitalArtworkVo getDigitalArtworkVoFromMdb(String uid, String skuId, String orderId) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("uid").is(uid).and("skuId").is(skuId).and("orderId").is(orderId)),
//                GoblinDigitalArtworkVo.class, GoblinDigitalArtworkVo.class.getSimpleName());
//    }
}
