package com.liquidnet.service.goblin.util;

import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtCouponFilterParam;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtGoodsFilterParam;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtNoticeFilterParam;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinMgtCategorySpecVo;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinStoreMgtCouponListVo;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinStoreMgtGoodsListVo;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinFrontBanner;
import com.liquidnet.service.goblin.entity.GoblinFrontHotWord;
import com.liquidnet.service.goblin.entity.GoblinFrontNavigation;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.UpdateOneModel;
import com.mongodb.client.model.WriteModel;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.convert.MongoConverter;
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.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS;

@Component
public class GoblinMongoUtils {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    MongoConverter mongoConverter;
    @Autowired
    GoblinRedisUtils redisUtils;

    /* ---------------------------------------- 平台分类数据源 ---------------------------------------- */

    public List<GoblinSelfGoodsCategoryVo> getSelfGoodsCategoryVos() {
        return mongoTemplate.findAll(GoblinSelfGoodsCategoryVo.class, GoblinSelfGoodsCategoryVo.class.getSimpleName());
    }

    /* ---------------------------------------- 店铺分类数据源 ---------------------------------------- */

    public void setStoreGoodsCategoryVos(List<GoblinStoreGoodsCategoryVo> vos) {
        mongoTemplate.insert(vos, GoblinStoreGoodsCategoryVo.class.getSimpleName());
    }

    public boolean updateStoreGoodsCategoryVo(GoblinStoreGoodsCategoryVo vo) {
        return mongoTemplate.getCollection(GoblinStoreGoodsCategoryVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("storeId").is(vo.getStoreId()).and("cateId").is(vo.getCateId())).getQueryObject(),
                ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
        ).getModifiedCount() > 0;
    }

    public List<GoblinStoreGoodsCategoryVo> getStoreGoodsCategoryVos(String storeId) {
        return mongoTemplate.find(Query.query(Criteria.where("storeId").is(storeId)),
                GoblinStoreGoodsCategoryVo.class, GoblinStoreGoodsCategoryVo.class.getSimpleName());
    }

    /* ---------------------------------------- 平台分类规格数据源 ---------------------------------------- */

    public void setCategorySpecVo(GoblinMgtCategorySpecVo vo) {
        mongoTemplate.insert(vo, GoblinMgtCategorySpecVo.class.getSimpleName());
    }

    public boolean updateCategorySpecVo(GoblinMgtCategorySpecVo vo) {
        return mongoTemplate.getCollection(GoblinMgtCategorySpecVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("cateId").is(vo.getCateId())).getQueryObject(),
                Update.update("specNameList", vo.getSpecNameList()).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public GoblinMgtCategorySpecVo getCategorySpecVo(String cateId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("cateId").is(cateId)),
                GoblinMgtCategorySpecVo.class, GoblinMgtCategorySpecVo.class.getSimpleName());
    }

    /* ---------------------------------------- 标签数据源 ---------------------------------------- */

    public List<GoblinSelfTagVo> getSelfTagVos(String keyword, String belong, Object[] typeRange) {
        Criteria criteria = Criteria.where("delFlg").is("0").and("tagBelong").is(belong);
        if (StringUtils.isNotBlank(keyword)) {
            criteria.and("tagName").regex("^.*" + keyword + ".*$");
        }
        if (belong.equals("1")) {
            criteria.and("tagType").in(typeRange);
        }
        return mongoTemplate.find(Query.query(criteria).skip(0).limit(20), GoblinSelfTagVo.class, GoblinSelfTagVo.class.getSimpleName());
    }

    /**
     * 标签全量数据
     *
     * @param belong 标签所属[0-普通标签|1-专属标签]
     * @return List<GoblinSelfTagVo>
     */
    public List<GoblinSelfTagVo> getSelfTagVos(String belong) {
        return mongoTemplate.find(Query.query(Criteria.where("delFlg").is("0").and("tagBelong").is(belong)),
                GoblinSelfTagVo.class, GoblinSelfTagVo.class.getSimpleName());
    }

    public List<GoblinSelfTagVo> getMgtSelfTagVos(List<String> tagIds) {
        if (CollectionUtils.isEmpty(tagIds)) return ObjectUtil.getGoblinSelfTagVoArrayList();
        return mongoTemplate.find(Query.query(Criteria.where("delFlg").is("0")),
                GoblinSelfTagVo.class, GoblinSelfTagVo.class.getSimpleName());
    }

//    public List<GoblinGoodsTagVo> getGoodsTagVos(List<String> tagIds) {
//        if (CollectionUtils.isEmpty(tagIds)) return ObjectUtil.getGoblinGoodsTagVoArrayList();
//
//        return null;
//    }
//
//    public List<GoblinGoodsExtagVo> getGoodsExtagVos(List<String> tagIds) {
//        if (CollectionUtils.isEmpty(tagIds)) return ObjectUtil.getGoblinGoodsExtagVoArrayList();
//
//        return null;
//    }

    /* ---------------------------------------- 服务保障数据源 ---------------------------------------- */

    public List<GoblinServiceSupportVo> getServiceSupportVos(List<String> ssids) {
        if (CollectionUtils.isEmpty(ssids)) return ObjectUtil.getGoblinServiceSupportVoArrayList();
        return mongoTemplate.find(Query.query(Criteria.where("ssid").in(ssids)),
                GoblinServiceSupportVo.class, GoblinServiceSupportVo.class.getSimpleName());
    }

    public List<GoblinServiceSupportVo> getMgtServiceSupportVos() {
        return mongoTemplate.findAll(GoblinServiceSupportVo.class, GoblinServiceSupportVo.class.getSimpleName());
    }

    public List<GoblinServiceSupportVo> insertMgtServiceSupportVos(List<GoblinServiceSupportVo> vos) {
        return (List<GoblinServiceSupportVo>) mongoTemplate.insert(vos, GoblinServiceSupportVo.class.getSimpleName());
    }

    /* ---------------------------------------- 店铺公告数据源 ---------------------------------------- */

    public PagedResult<GoblinStoreNoticeVo> getStoreNoticeVos(GoblinStoreMgtNoticeFilterParam filterParam) {
        Criteria criteria = Criteria.where("storeId").is(filterParam.getStoreId()).and("delFlg").is("0");
        if (StringUtils.isNotBlank(filterParam.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + filterParam.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            criteria.and("content").regex(pattern);
        }
        Query query = Query.query(criteria);

        long count = mongoTemplate.count(query, GoblinStoreNoticeVo.class.getSimpleName());

        PagedResult<GoblinStoreNoticeVo> pagedResult = ObjectUtil.getGoblinStoreNoticeVoPagedResult();
        if (count <= 0) return pagedResult;

        query.with(PageRequest.of(filterParam.getPageNum() - 1, filterParam.getPageSize()));
        query.with(Sort.by(Sort.Order.desc("createdAt")));

        List<GoblinStoreNoticeVo> storeNoticeVos = mongoTemplate.find(query, GoblinStoreNoticeVo.class, GoblinStoreNoticeVo.class.getSimpleName());
        return pagedResult.setList(storeNoticeVos).setTotal(count, filterParam.getPageSize());
    }

    /**
     * 查取指定店铺有效的公告通知
     *
     * @param storeId 店铺ID
     * @return List<GoblinStoreNoticeVo>
     */
    public List<GoblinStoreNoticeVo> getStoreNoticeVos(String storeId, LocalDateTime nowTime) {
        return mongoTemplate.find(Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0")
                        .orOperator(
                                Criteria.where("releaseTime").gte(nowTime),
                                Criteria.where("longLasting").is("0").and("cancellTime").gte(nowTime),
                                Criteria.where("longLasting").is("1")
                        )
                ).with(Sort.by(Sort.Order.asc("releaseTime"), Sort.Order.asc("createdAt"))),
                GoblinStoreNoticeVo.class, GoblinStoreNoticeVo.class.getSimpleName());
    }

    public void setStoreNoticeVo(GoblinStoreNoticeVo vo) {
        mongoTemplate.insert(vo, GoblinStoreNoticeVo.class.getSimpleName());
    }

    public boolean updateStoreNoticeVo(GoblinStoreNoticeVo vo) {
        return mongoTemplate.getCollection(GoblinStoreNoticeVo.class.getSimpleName())
                .updateOne(
                        Query.query(Criteria.where("storeId").is(vo.getStoreId()).and("delFlg").is("0").and("noticeId").is(vo.getNoticeId())).getQueryObject(),
                        ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
                ).getModifiedCount() > 0;
    }

    public boolean updateStoreNoticeVoByBulk(List<GoblinStoreNoticeVo> vos) {
        List<WriteModel<Document>> list = ObjectUtil.getWriteModelDocumentArrayList();
        vos.forEach(r -> {
            if (StringUtils.isNotEmpty(r.getStoreId())) {
                list.add(new UpdateOneModel<>(
                        Query.query(Criteria.where("storeId").is(r.getStoreId()).and("noticeId").is(r.getNoticeId())).getQueryObject(),
                        Update.update("releaseTime", r.getReleaseTime()).set("status", r.getStatus()).set("updatedBy", r.getUpdatedBy()).set("updatedAt", r.getUpdatedAt()).getUpdateObject()
                ));
            }
        });
        return mongoTemplate.getCollection(GoblinStoreNoticeVo.class.getSimpleName()).bulkWrite(list).getModifiedCount() > 0;
    }

    public boolean updateStoreNoticeVoByRelease(String uid, LocalDateTime nowTime, String storeId, List<String> noticeIdList) {
        return mongoTemplate.getCollection(GoblinStoreNoticeVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("noticeId").in(noticeIdList.toArray()).and("status").is("0")).getQueryObject(),
                Update.update("status", "1").set("releaseTime", nowTime).set("updatedBy", uid).set("updatedAt", nowTime).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean updateStoreNoticeVoByRemove(String uid, LocalDateTime nowTime, String storeId, List<String> noticeIdList) {
        return mongoTemplate.getCollection(GoblinStoreNoticeVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("noticeId").in(noticeIdList.toArray())).getQueryObject(),
                Update.update("delFlg", "1").set("updatedBy", uid).set("updatedAt", nowTime).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    /* ---------------------------------------- 店铺配置数据源 ---------------------------------------- */

    public List<GoblinStoreConfigVo> getStoreConfigVos(String storeId) {
        Query query = Query.query(Criteria.where("storeId").is(storeId));
        query.fields().include("storeId").include("configKey").include("configVal");
        return mongoTemplate.find(query,
                GoblinStoreConfigVo.class, GoblinStoreConfigVo.class.getSimpleName());
    }

    public boolean updateStoreConfigVos(List<GoblinStoreConfigVo> vos) {
        List<WriteModel<Document>> list = ObjectUtil.getWriteModelDocumentArrayList();
        vos.forEach(r -> {
            if (StringUtils.isNotEmpty(r.getStoreId())) {
                list.add(new UpdateOneModel<>(
                        Query.query(Criteria.where("storeId").is(r.getStoreId()).and("configKey").is(r.getConfigKey())).getQueryObject(),
                        Update.update("configVal", r.getConfigVal()).set("updatedBy", r.getUpdatedBy()).set("updatedAt", r.getUpdatedAt()).getUpdateObject()
                ));
            }
        });
        return mongoTemplate.getCollection(GoblinStoreConfigVo.class.getSimpleName()).bulkWrite(list).getModifiedCount() > 0;
    }

    public List<GoblinStoreConfigVo> delStoreConfigVo(String storeId) {
        Query query = Query.query(Criteria.where("storeId").is(storeId));
        query.fields().include("configKey").include("configVal");
        return mongoTemplate.find(query,
                GoblinStoreConfigVo.class, GoblinStoreConfigVo.class.getSimpleName());
    }

    /* ---------------------------------------- 店铺数据源 ---------------------------------------- */

    public GoblinStoreInfoVo setStoreInfoVo(GoblinStoreInfoVo vo) {
        return mongoTemplate.insert(vo, GoblinStoreInfoVo.class.getSimpleName());
    }

    public boolean delStoreInfoVo(String storeId, String uid, LocalDateTime time) {
        return mongoTemplate.updateFirst(Query.query(Criteria.where("storeId").is(storeId)),
                Update.update("delFlg", "1").set("updatedBy", uid).set("updatedAt", time).set("deletedBy", uid).set("deletedAt", time),
                GoblinStoreInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

    public boolean updateStoreInfoVo(GoblinStoreInfoVo vo) {
        return mongoTemplate.getCollection(GoblinStoreInfoVo.class.getSimpleName())
                .updateOne(Query.query(Criteria.where("storeId").is(vo.getStoreId())).getQueryObject(),
                        ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
                ).getModifiedCount() > 0;
    }

    public GoblinStoreInfoVo getStoreInfoVo(String storeId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0")),
                GoblinStoreInfoVo.class, GoblinStoreInfoVo.class.getSimpleName());
    }

    public ArrayList<String> getStoreInfoVoRegexName(String storeName) {
        Query query = Query.query(Criteria.where("storeName").regex("^.*" + storeName + ".*$").and("delFlg").is("0").and("status").in("3", "5"));
        query.fields().include("storeId");
        List<GoblinStoreInfoVo> voList = mongoTemplate.find(query, GoblinStoreInfoVo.class, GoblinStoreInfoVo.class.getSimpleName());
        ArrayList<String> list = CollectionUtil.arrayListString();
        for (GoblinStoreInfoVo goblinStoreInfoVo : voList) {
            list.add(goblinStoreInfoVo.getStoreId());
        }
        return list;
    }

    public List<GoblinStoreInfoVo> getStoreInfoVoByUid(String uid) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("uid").is(uid).and("delFlg").is("0")),
//                GoblinStoreInfoVo.class, GoblinStoreInfoVo.class.getSimpleName());
        return mongoTemplate.find(Query.query(Criteria.where("uid").is(uid).and("delFlg").is("0")),
                GoblinStoreInfoVo.class, GoblinStoreInfoVo.class.getSimpleName());
    }

    /* ---------------------------------------- 商品数据源 ---------------------------------------- */

    // SPU信息
    public GoblinGoodsInfoVo setGoodsInfoVo(GoblinGoodsInfoVo vo) {
        return mongoTemplate.insert(vo, GoblinGoodsInfoVo.class.getSimpleName());
    }

    public void upsertGoodsInfoVo(GoblinGoodsInfoVo vo) {
        Document document = (Document) mongoConverter.convertToMongoType(vo);
        Update update = Update.fromDocument(document);
        mongoTemplate.upsert(Query.query(Criteria.where("storeId").is(vo.getStoreId()).and("spuId").is(vo.getSpuId())), update, GoblinGoodsInfoVo.class.getSimpleName());
    }

    public boolean delGoodsInfoVo(String spuId) {
        return mongoTemplate.getCollection(GoblinGoodsInfoVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0")).getQueryObject(),
                Update.update("delFlg", "1").getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean delGoodsSkuInfoVo(String skuId) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("skuId").is(skuId).and("delFlg").is("0")).getQueryObject(),
                Update.update("delFlg", "1").getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean delGoodsInfoVoBySpuIds(String storeId, List<String> spuIdList, String uid, LocalDateTime time) {
        return mongoTemplate.updateMulti(
                Query.query(Criteria.where("storeId").is(storeId).and("spuId").in(spuIdList).and("delFlg").is("0")),
                Update.update("delFlg", "1").set("updatedBy", uid).set("updatedAt", time).set("deletedBy", uid).set("deletedAt", time),
                GoblinGoodsInfoVo.class.getSimpleName()
        ).getModifiedCount() > 0;
    }

    public List<String> delGoodsInfoVoByStoreId(String storeId, String uid, LocalDateTime time) {
        Query query = Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("shelvesStatus").is("3"));
        query.fields().include("spuId");
        List<GoblinGoodsInfoVo> storeSpus = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());

        List<String> storeSpuIdList = CollectionUtil.arrayListString();
        if (!CollectionUtils.isEmpty(storeSpus)) {
            storeSpuIdList = storeSpus.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
            UpdateResult updateResult = mongoTemplate.updateMulti(Query.query(Criteria.where("spuId").in(storeSpuIdList)),
                    Update.update("delFlg", "1").set("updatedBy", uid).set("updatedAt", time).set("deletedBy", uid).set("deletedAt", time),
                    GoblinGoodsInfoVo.class.getSimpleName());
            if (updateResult.getModifiedCount() > 0) {
                return storeSpuIdList;
            }
        }
        return storeSpuIdList;
    }

    // SPU分页
    public PagedResult<GoblinStoreMgtGoodsListVo> getMgtGoodsInfoVos(GoblinStoreMgtGoodsFilterParam filterParam) {
        Criteria criteria = Criteria.where("delFlg").is("0").and("storeId").is(filterParam.getStoreId()).and("marketId").exists(false);
        if (null != filterParam.getSpuType()) {
            if (0 == filterParam.getSpuType()) {
                criteria.andOperator(Criteria.where("spuType").exists(false).orOperator(Criteria.where("spuType").is(0)));
            } else {
                criteria.and("spuType").is(1);
            }
        }
        if (StringUtils.isNotBlank(filterParam.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + filterParam.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            criteria.and("name").regex(pattern);
        }
        if (StringUtils.isNotBlank(filterParam.getShelvesStatus())) {
            criteria.and("shelvesStatus").is(filterParam.getShelvesStatus());
        }
        if (StringUtils.isNotBlank(filterParam.getCateFid())) {
            criteria.and("cateFid").is(filterParam.getCateFid());
        }
        if (StringUtils.isNotBlank(filterParam.getCateSid())) {
            criteria.and("cateSid").is(filterParam.getCateSid());
        }
        if (StringUtils.isNotBlank(filterParam.getCateTid())) {
            criteria.and("cateTid").is(filterParam.getCateTid());
        }
        if (StringUtils.isNotBlank(filterParam.getCreatedDt())) {
            LocalDateTime createDt = DateUtil.Formatter.yyyy_MM_dd.parse(filterParam.getCreatedDt());
            LocalDateTime createdAtBegin = createDt.withHour(0).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime createdAtEnd = createDt.withHour(23).withMinute(59).withSecond(59).withNano(999);

            criteria.and("createdAt").gte(createdAtBegin).lte(createdAtEnd);
        }
        if (null != filterParam.getPriceGe()) {
            criteria.and("priceGe").gte(filterParam.getPriceGe());
        }
        if (null != filterParam.getPriceLe()) {
            criteria.and("priceLe").lte(filterParam.getPriceLe());
        }
        Query query = Query.query(criteria);

        long count = mongoTemplate.count(query, GoblinGoodsInfoVo.class.getSimpleName());

        PagedResult<GoblinStoreMgtGoodsListVo> pagedResult = ObjectUtil.getGoblinStoreMgtGoodsVoPagedResult();
        if (count <= 0) return pagedResult;

        query.with(PageRequest.of(filterParam.getPageNum() - 1, filterParam.getPageSize()));
        query.with(Sort.by(Sort.Order.desc("createdAt")));

        List<GoblinStoreMgtGoodsListVo> goodsListVos = mongoTemplate.find(query, GoblinStoreMgtGoodsListVo.class, GoblinGoodsInfoVo.class.getSimpleName());

        return pagedResult.setList(goodsListVos).setTotal(count, filterParam.getPageSize());
    }

    public List<String> getMgtSpuNosForMarketBySpuNos(List<String> spuNos, Object... shelvesStatus) {
        Query query = Query.query(Criteria.where("spuNo").in(spuNos.toArray())
                .and("marketId").exists(true).and("delFlg").is("0").and("shelvesStatus").in(shelvesStatus));
        query.fields().include("spuNo");
        List<GoblinGoodsInfoVo> goblinGoodsInfoVos = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        return CollectionUtils.isEmpty(goblinGoodsInfoVos) ? CollectionUtil.arrayListString() : goblinGoodsInfoVos.stream().map(GoblinGoodsInfoVo::getSpuNo).distinct().collect(Collectors.toList());
    }

    public List<String> getMgtSpuIdsForMarketBySpuNos(List<String> spuNos, Object... shelvesStatus) {
        Query query = Query.query(Criteria.where("spuNo").in(spuNos.toArray())
                .and("marketId").exists(true).and("delFlg").is("0").and("shelvesStatus").in(shelvesStatus));
        query.fields().include("spuId");
        List<GoblinGoodsInfoVo> goblinGoodsInfoVos = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        return CollectionUtils.isEmpty(goblinGoodsInfoVos) ? CollectionUtil.arrayListString() : goblinGoodsInfoVos.stream().map(GoblinGoodsInfoVo::getSpuId).distinct().collect(Collectors.toList());
    }

    // SPU信息
    public List<String> getMgtGoodsSpuIds(String storeId) {
        Query query = Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0"));
        query.fields().include("spuId");
        List<GoblinGoodsInfoVo> vos = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        return CollectionUtils.isEmpty(vos) ? CollectionUtil.arrayListString()
                : vos.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
    }

    // SPU信息
    public GoblinGoodsInfoVo getGoodsInfoVo(String spuId) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0").and("shelvesStatus").is("3")),
//        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0")),
        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId)),
                GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
    }

    // SPU信息
//    public GoblinGoodsInfoVo getMgtGoodsInfoVo(String spuId) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0")),
//                GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
//    }

    // SPU信息
    public GoblinGoodsInfoVo getMgtGoodsInfoVo(String storeId, String name) {
        return mongoTemplate.findOne(Query.query(Criteria.where("storeId").is(storeId).and("name").is(name).and("delFlg").is("0")),
                GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
    }

    public long countMgtGoodsInfoVo(String name) {
        return mongoTemplate.count(Query.query(Criteria.where("name").is(name).and("delFlg").is("0")),
                GoblinGoodsInfoVo.class.getSimpleName());
    }

    // SPU信息
    public boolean updateGoodsInfoVo(GoblinGoodsInfoVo vo) {
        return mongoTemplate.getCollection(GoblinGoodsInfoVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("spuId").is(vo.getSpuId()).and("delFlg").is("0")).getQueryObject(),
                ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
        ).getModifiedCount() > 0;
    }

    // SPU活动商品信息更新
    public List<String> updateGoodsInfoVoForMarket(String spuId, String spuNo, GoblinGoodsInfoVo vo) {
        Query query = Query.query(Criteria.where("spuNo").is(spuNo).and("delFlg").is("0").and("spuId").ne(spuId));
        query.fields().include("spuId");
        List<GoblinGoodsInfoVo> marketGoodsInfoVos = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        if (!CollectionUtils.isEmpty(marketGoodsInfoVos)) {
            List<String> marketSpuIds = marketGoodsInfoVos.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
            mongoTemplate.getCollection(GoblinGoodsInfoVo.class.getSimpleName()).updateMany(
                    Query.query(Criteria.where("spuId").in(marketSpuIds).and("delFlg").is("0")).getQueryObject(),
                    Update.update("spuNo", vo.getSpuNo())
                            .set("name", vo.getName())
                            .set("subtitle", vo.getSubtitle())
                            .set("sellPrice", vo.getSellPrice())
                            .set("intro", vo.getIntro())
                            .set("details", vo.getDetails())
                            .set("coverPic", vo.getCoverPic())
                            .set("video", vo.getVideo())
                            .set("specMode", "2")
                            .set("cateFid", vo.getCateFid())
                            .set("cateSid", vo.getCateSid())
                            .set("cateTid", vo.getCateTid())
                            .set("shelvesHandle", vo.getShelvesHandle())
                            .set("shelvesTime", vo.getShelvesTime())
                            .set("spuValidity", vo.getSpuValidity())
                            .set("virtualFlg", vo.getVirtualFlg())
                            .set("imageList", mongoConverter.convertToMongoType(vo.getImageList()))
                            .set("logisticsTemplate", vo.getLogisticsTemplate())
                            .set("tagVoList", mongoConverter.convertToMongoType(vo.getTagVoList()))
                            .set("extagVoList", mongoConverter.convertToMongoType(vo.getExtagVoList()))
                            .set("artagVoList", mongoConverter.convertToMongoType(vo.getArtagVoList()))
                            .set("serviceSupportVoList", mongoConverter.convertToMongoType(vo.getServiceSupportVoList()))
                            .set("updatedBy", vo.getUpdatedBy())
                            .set("updatedAt", vo.getUpdatedAt())
                            .getUpdateObject()
            );
            return marketSpuIds;
        }
        return null;
    }

    // SPU信息
    public boolean updateGoodsInfoVoAppear(String storeId, String spuAppear, LocalDateTime time, String uid) {
        return mongoTemplate.getCollection(GoblinGoodsInfoVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0")).getQueryObject(),
                Update.update("spuAppear", spuAppear).set("updatedBy", uid).set("updatedAt", time).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean updateGoodsInfoVoByShelves(String storeId, List<String> spuIdList, boolean shelvesFlg, String uid, LocalDateTime time) {
        Update update = Update.update("shelvesStatus", shelvesFlg ? "3" : "1").set("shelvesAt", time).set("updatedBy", uid).set("updatedAt", time);
        if (!shelvesFlg) {
            update.set("shelvesHandle", "1");
        }
        return mongoTemplate.updateMulti(Query.query(Criteria.where("storeId").is(storeId).and("spuId").in(spuIdList.toArray())),
                update,
                GoblinGoodsInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

    // SKU信息
    public GoblinGoodsSkuInfoVo setGoodsSkuInfoVo(GoblinGoodsSkuInfoVo vo) {
        return mongoTemplate.insert(vo, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    public UpdateResult upsertGoodsSkuInfoVo(GoblinGoodsSkuInfoVo vo) {
        Document document = (Document) mongoConverter.convertToMongoType(vo);
        Update update = Update.fromDocument(document);
        Query query = Query.query(Criteria.where("storeId").is(vo.getStoreId()).and("skuId").is(vo.getSkuId()));
        UpdateResult result = mongoTemplate.upsert(query, update, GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
        return result;
    }

    // SKU信息
    public List<GoblinGoodsSkuInfoVo> setGoodsSkuInfoVos(List<GoblinGoodsSkuInfoVo> vos) {
        return (List<GoblinGoodsSkuInfoVo>) mongoTemplate.insert(vos, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    public boolean delGoodsSkuInfoVo(List<String> skuIdList, String operator, LocalDateTime time) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("skuId").in(skuIdList).and("delFlg").is("0")).getQueryObject(),
                Update.update("delFlg", "1").set("updatedBy", operator).set("updatedAt", time)
                        .set("deletedBy", operator).set("deletedAt", time).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public List<String> delGoodsSkuInfoVoByStoreId(String storeId, String uid, LocalDateTime time) {
        Query query = Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("shelvesStatus").is("3"));
        query.fields().include("skuId");
        List<GoblinGoodsSkuInfoVo> storeSkus = mongoTemplate.find(query, GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());

        List<String> storeSkuIdList = CollectionUtil.arrayListString();
        if (!CollectionUtils.isEmpty(storeSkus)) {
            storeSkuIdList = storeSkus.stream().map(GoblinGoodsSkuInfoVo::getSkuId).collect(Collectors.toList());
            UpdateResult updateResult = mongoTemplate.updateMulti(Query.query(Criteria.where("skuId").in(storeSkuIdList)),
                    Update.update("delFlg", "1").set("updatedBy", uid).set("updatedAt", time).set("deletedBy", uid).set("deletedAt", time),
                    GoblinGoodsSkuInfoVo.class.getSimpleName());
            if (updateResult.getModifiedCount() > 0) {
                return storeSkuIdList;
            }
        }
        return storeSkuIdList;
    }

    // SKU信息
    public GoblinGoodsSkuInfoVo getGoodsSkuInfoVo(String skuId) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId).and("delFlg").is("0").and("shelvesStatus").is("3")),
//        return mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId).and("delFlg").is("0")),
        return mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId)),
                GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    public List<GoblinGoodsSkuInfoVo> getGoodsSkuInfoVos(List<String> skuIds) {
        return mongoTemplate.find(Query.query(Criteria.where("skuId").in(skuIds)),
                GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    // SKU信息
    public List<String> getMgtGoodsSkuIds(String storeId, List<String> spuIdList) {
        Query query = Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("spuId").in(spuIdList.toArray()));
        query.fields().include("skuId");
        List<GoblinGoodsSkuInfoVo> vos = mongoTemplate.find(query, GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
        return CollectionUtils.isEmpty(vos) ? CollectionUtil.arrayListString()
                : vos.stream().map(GoblinGoodsSkuInfoVo::getSkuId).collect(Collectors.toList());
    }

    // SKU信息
//    public GoblinGoodsSkuInfoVo getMgtGoodsSkuInfoVo(String skuId) {
//        return mongoTemplate.findOne(Query.query(Criteria.where("skuId").is(skuId).and("delFlg").is("0")),
//                GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
//    }

    // SKU信息
    public boolean updateGoodsSkuInfoVo(GoblinGoodsSkuInfoVo vo) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName())
                .updateOne(
                        Query.query(Criteria.where("skuId").is(vo.getSkuId()).and("delFlg").is("0")).getQueryObject(),
                        ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
                ).getModifiedCount() > 0;
    }

    // SKU活动商品信息更新
    public boolean updateGoodsSkuInfoVoForMarket(List<String> skuIds, GoblinGoodsSkuInfoVo vo) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("skuId").in(skuIds).and("delFlg").is("0")).getQueryObject(),
                Update.update("name", vo.getName())
                        .set("skuPic", vo.getSkuPic())
                        .set("skuSpecList", mongoConverter.convertToMongoType(vo.getSkuSpecList()))
                        .set("sellPrice", vo.getSellPrice())
//                        .set("price", vo.getPrice())
//                        .set("priceMember", vo.getPriceMember())
                        .set("weight", vo.getWeight())
                        .set("stock", vo.getStock())
//                        .set("skuStock", vo.getSkuStock())
                        .set("warningStock", vo.getWarningStock())
                        .set("skuAppear", vo.getSkuAppear())
                        .set("skuIsbn", vo.getSkuIsbn())
//                        .set("buyFactor", vo.getBuyFactor())
//                        .set("buyRoster", vo.getBuyRoster())
//                        .set("buyLimit", vo.getBuyLimit())
                        .set("skuValidity", vo.getSkuValidity())
                        .set("updatedBy", vo.getUpdatedBy())
                        .set("updatedAt", vo.getUpdatedAt())
                        .getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean updateGoodsSkuInfoVoBySpuId(GoblinGoodsSkuInfoVo vo) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("spuId").is(vo.getSpuId()).and("delFlg").is("0")).getQueryObject(),
                ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
        ).getModifiedCount() > 0;
    }

    public boolean updateGoodsSkuInfoVoByShelves(String storeId, List<String> spuIdList, boolean shelvesFlg, String uid, LocalDateTime time) {
        return mongoTemplate.updateMulti(Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("spuId").in(spuIdList.toArray())),
                Update.update("shelvesStatus", shelvesFlg ? "3" : "1").set("shelvesAt", time).set("updatedBy", uid).set("updatedAt", time),
                GoblinGoodsSkuInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

    public boolean updateGoodsSkuInfoVoByShelvesSku(String storeId, List<String> skuIdList, boolean shelvesFlg, String uid, LocalDateTime time) {
        return mongoTemplate.updateMulti(Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("skuId").in(skuIdList)),
                Update.update("shelvesStatus", shelvesFlg ? "3" : "1").set("shelvesAt", time).set("updatedBy", uid).set("updatedAt", time),
                GoblinGoodsSkuInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

    public boolean updateGoodsSkuInfoVoBySoldoutSku(String storeId, List<String> skuIdList, String soldoutStatus, String uid, LocalDateTime time) {
        return mongoTemplate.updateMulti(Query.query(Criteria.where("storeId").is(storeId).and("delFlg").is("0").and("skuId").in(skuIdList)),
                Update.update("soldoutStatus", soldoutStatus).set("updatedBy", uid).set("updatedAt", time),
                GoblinGoodsSkuInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

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

    /**
     * 添加 商铺活动 mongo
     *
     * @param data
     * @return
     */
    public GoblinStoreMarketVo insertStoreMarket(GoblinStoreMarketVo data) {
        return mongoTemplate.insert(data, GoblinStoreMarketVo.class.getSimpleName());
    }

    /**
     * 修改 商铺活动 mongo
     *
     * @param marketId
     * @param data
     * @return
     */
    public UpdateResult updateStoreMarket(String marketId, String storeId, GoblinStoreMarketVo data) {
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(data));
        return mongoTemplate.getCollection(GoblinStoreMarketVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("storeMarketId").is(marketId).and("storeId").is(storeId)).getQueryObject(),
                object);
    }

    /**
     * 获取 商铺活动 mongo
     *
     * @param marketId
     * @return
     */
    public GoblinStoreMarketVo getStoreMarket(String marketId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("storeMarketId").is(marketId)), GoblinStoreMarketVo.class, GoblinStoreMarketVo.class.getSimpleName());
    }

    /**
     * 删除 商铺活动 mongo
     *
     * @param marketId
     * @param storeId
     * @return
     */
    public DeleteResult delStoreMarket(String marketId, String storeId) {
        return mongoTemplate.remove(Query.query(Criteria.where("storeMarketId").is(marketId).and("storeId").is(storeId)), GoblinStoreMarketVo.class.getSimpleName());
    }


    /**
     * 获取 商铺活动列表
     *
     * @param page
     * @param purchaseName
     * @param status
     * @param st
     * @param et
     * @param ct
     * @return
     */
    public HashMap<String, Object> getStoreMarketList(int page, String purchaseName, int status, String st, String et, String ct) {
        String nowStr = DateUtil.getNowTime();
        int size = 40;
        HashMap<String, Object> info = CollectionUtil.mapStringObject();
        // 排序 分页
        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        //条件
        Criteria criteria = new Criteria();
        if (purchaseName != null) {
            criteria = criteria.and("name").regex(".*?\\" + purchaseName);
        }
        if (st != null && et != null) {
            criteria = criteria.and("endTime").lte(et).and("startTime").gte(st);
        }
        if (ct != null) {
            criteria = criteria.and("createdAt").regex(".*?\\" + ct);
        }

        switch (status) {
            case 0:
                criteria = criteria.and("startTime").gte(nowStr);
                break;
            case 1:
                criteria = criteria.and("endTime").gte(nowStr).and("startTime").lte(nowStr);
                break;
            case 2:
                criteria = criteria.and("endTime").lte(nowStr);
                break;
            case 7:
                criteria = criteria.and("status").lte(7);
                break;
        }
        Query query = Query.query(criteria);
        // 查询总数
        long count = mongoTemplate.count(query, GoblinStoreMarketVo.class, GoblinStoreMarketVo.class.getSimpleName());
        query.with(pageable);
        List<GoblinStoreMarketVo> voList = mongoTemplate.find(query, GoblinStoreMarketVo.class, GoblinStoreMarketVo.class.getSimpleName());
        info.put("total", count);
        info.put("data", voList);
        return info;
    }

    //获取全部正在下单的活动
    public List<GoblinSelfMarketingVo> getGoblinSelfMarketingVoList() {
        String nowStr = DateUtil.getNowTime();
        List<GoblinSelfMarketingVo> voList = mongoTemplate.find(Query.query(Criteria.where("type").is(2).and("status").ne(7).and("endTime").gte(nowStr).and("startTime").lte(nowStr)), GoblinSelfMarketingVo.class, GoblinSelfMarketingVo.class.getSimpleName());
        return voList;
    }

    //添加 订单vo全量
    public GoblinStoreOrderVo insertGoblinStoreOrderVo(GoblinStoreOrderVo vo) {
        return mongoTemplate.insert(vo, GoblinStoreOrderVo.class.getSimpleName());
    }

    public UpdateResult updateGoblinStoreOrderVo(String orderId, GoblinStoreOrderVo data) {
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(data));
        return mongoTemplate.getCollection(GoblinStoreOrderVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("orderId").is(orderId)).getQueryObject(),
                object);
    }

    //添加 订单SkuVo全量
    public GoblinOrderSkuVo insertGoblinOrderSkuVo(GoblinOrderSkuVo vo) {
        return mongoTemplate.insert(vo, GoblinOrderSkuVo.class.getSimpleName());
    }

    public UpdateResult updateGoblinOrderSkuVo(String orderSkuId, GoblinOrderSkuVo data) {
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(data));
        return mongoTemplate.getCollection(GoblinOrderSkuVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("orderSkuId").is(orderSkuId)).getQueryObject(),
                object);
    }

    //添加 订单SkuVo全量
    public GoblinMailVo insertGoblinMailVo(GoblinMailVo vo) {
        return mongoTemplate.insert(vo, GoblinMailVo.class.getSimpleName());
    }

    public UpdateResult updateGoblinMailVo(String mailId, GoblinMailVo data) {
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(data));
        return mongoTemplate.getCollection(GoblinMailVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("mailId").is(mailId)).getQueryObject(),
                object);
    }

    //添加 操作日志
    public GoblinOrderLogVo insertGoblinOrderLogVo(GoblinOrderLogVo vo) {
        return mongoTemplate.insert(vo, GoblinOrderLogVo.class.getSimpleName());
    }

    //添加 订单退款数据
    public GoblinBackOrderVo insertGoblinBackOrderVo(GoblinBackOrderVo vo) {
        return mongoTemplate.insert(vo, GoblinBackOrderVo.class.getSimpleName());
    }

    //修改 订单退款数据
    public UpdateResult updateGoblinBackOrderVo(String backOrderId, GoblinBackOrderVo data) {
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(data));
        return mongoTemplate.getCollection(GoblinBackOrderVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("backOrderId").is(backOrderId)).getQueryObject(),
                object);
    }

    //获取 订单退款数据根据orderCode
    public GoblinBackOrderVo getGoblinBackOrderVoByBackCode(String backCode) {
        return mongoTemplate.findOne(Query.query(Criteria.where("backCode").is(backCode)), GoblinBackOrderVo.class, GoblinBackOrderVo.class.getSimpleName());
    }

    //获取 正在下单活动内容列表
    public List<GoblinGoodsInfoVo> marketSpuList(String marketId, String storeId, int start, int skip) {
        List<GoblinGoodsInfoVo> list = mongoTemplate.find(Query.query(Criteria.where("storeId").is(storeId).and("marketId").is("ZZ" + marketId).and("delFlg").is("0").and("shelvesStatus").is("3")).with(Sort.by(Sort.Order.desc("createdAt"))).skip(start).limit(skip), GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        return list;
    }

    //店铺总收入
    public String storeMoney(String storeId, String spuId, String st, String et) {
        String spuName = "店铺总收入";
        Criteria criteria = Criteria.where("status").in(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue(), GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue(), GoblinStatusConst.Status.ORDER_LOG_STATUS_28.getValue()).and("storeId").is(storeId);
        if (st != null && et != null) {
            LocalDateTime stDateTime = LocalDateTime.parse(st, DTF_YMD_HMS);
            LocalDateTime etDateTime = LocalDateTime.parse(et, DTF_YMD_HMS);
            criteria = criteria.and("createdAt").gte(stDateTime).lt(etDateTime);
        }
        Aggregation aggregation;
        if (spuId != null) {
            criteria = criteria.and("spuId").is(spuId);
            Query query = Query.query(Criteria.where("spuId").is(spuId));
            query.fields().include("name");
            GoblinGoodsInfoVo spuIdAndName = mongoTemplate.findOne(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
            if (spuIdAndName == null) {
                return "," + BigDecimal.ZERO;
            } else {
                spuName = spuIdAndName.getName();
            }
            aggregation = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.group("spuId")
                            .first("spuId").as("spuId")
                            .sum("skuPriceActual").as("skuPriceActual"));
//            aggregation = Aggregation.newAggregation(
//                    Aggregation.match(criteria),
//                    Aggregation.project("spuId", "skuPriceActual"),
//                    Aggregation.group("spuId")
//                            .first("spuId").as("spuId")
//                            .sum("skuPriceActual").as("skuPriceActual")
//            );
        } else {
            aggregation = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.group("storeId")
                            .first("storeId").as("storeId")
                            .sum("skuPriceActual").as("skuPriceActual"));
        }
        AggregationResults<GoblinOrderLogVo> outputType = mongoTemplate.aggregate(aggregation, GoblinOrderLogVo.class.getSimpleName(), GoblinOrderLogVo.class);
        List<GoblinOrderLogVo> dataList = new ArrayList(outputType.getMappedResults());
        if (dataList.size() > 0) {
            return spuName + "," + dataList.get(0).getSkuPriceActualBig();
        } else {
            return "," + BigDecimal.ZERO;
        }
    }

    //资金列表
    public HashMap<String, Object> moneyGetSpuList(String spuName, String st, String et, String storeId, int page) {
        //查询销量
        int size = 20;
        int skipCount = ((page - 1) * size);
        int finalCount = skipCount + size;
        List<GoblinGoodsInfoVo> spuIdAndName = null;
        Criteria criteria = Criteria.where("status").in(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue(), GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue(), GoblinStatusConst.Status.ORDER_LOG_STATUS_28.getValue()).and("storeId").is(storeId);
        if (st != null && et != null) {
            LocalDateTime stDateTime = LocalDateTime.parse(st, DTF_YMD_HMS);
            LocalDateTime etDateTime = LocalDateTime.parse(et, DTF_YMD_HMS);
            criteria = criteria.and("createdAt").gte(stDateTime).lt(etDateTime);
        }
        //查询总数量
        Query countQuery = Query.query(criteria).with(Sort.by(Sort.Order.desc("createdAt")));
        countQuery.fields().include("spuId");
        List<GoblinOrderLogVo> countList = mongoTemplate.find(countQuery, GoblinOrderLogVo.class, GoblinOrderLogVo.class.getSimpleName());
        List<String> spuIdList = countList.stream().map(GoblinOrderLogVo::getSpuId).distinct().collect(Collectors.toList());
        long total = spuIdList.size();
        if (finalCount > total) {
            finalCount = (int) total;
        }
        if (spuName != null) {
            //根据spu名称查询spuId
            Query query = Query.query(Criteria.where("name").regex(".*?" + spuName + ".*").and("storeId").is(storeId)).with(Sort.by(Sort.Order.desc("createdAt")));
            query.fields().include("spuId").include("name");
            spuIdAndName = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
            spuIdList = spuIdAndName.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
            if (finalCount > spuIdList.size()) {
                finalCount = spuIdList.size();
            }
        }
        if (finalCount > 0) {
            spuIdList = spuIdList.subList(skipCount, finalCount);
        }
        criteria = criteria.and("spuId").in(spuIdList);

        //查询聚合数据
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.project("spuId", "skuPriceActual","orderType"),
                Aggregation.group("spuId")
                        .first("spuId").as("spuId")
                        .first("orderType").as("orderType")
                        .sum("skuPriceActual").as("skuPriceActual"),
                Aggregation.sort(Sort.by(Sort.Order.desc("spuId")))
        );
        AggregationResults<GoblinOrderLogVo> outputType = mongoTemplate.aggregate(aggregation, GoblinOrderLogVo.class.getSimpleName(), GoblinOrderLogVo.class);
        List<GoblinOrderLogVo> dataList = new ArrayList(outputType.getMappedResults());
        if (spuIdAndName == null) {
            Query query = Query.query(Criteria.where("spuId").in(dataList.stream().map(GoblinOrderLogVo::getSpuId).collect(Collectors.toList())));
            query.fields().include("spuId").include("name");
            spuIdAndName = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
        }
        //处理数据
        for (GoblinOrderLogVo item : dataList) {
            for (GoblinGoodsInfoVo item2 : spuIdAndName) {
                if (item.getSpuId().equals(item2.getSpuId())) {
                    item.setSpuName(item2.getName());
                    break;
                }
            }
        }
        HashMap<String, Object> map = CollectionUtil.mapStringObject();
        map.put("data", dataList);
        map.put("total", total);
        return map;
    }

    //商品订单操作日志列表
    public HashMap<String, Object> moneyGetSpuDetails(String spuId, String orderCode, Integer type, String st, String et, int page) {
        //查询销量
        int size = 20;
        int skipCount = ((page - 1) * size);
        Criteria criteria = Criteria.where("spuId").is(spuId);
        if (st != null && et != null) {
            LocalDateTime stDateTime = LocalDateTime.parse(st, DTF_YMD_HMS);
            LocalDateTime etDateTime = LocalDateTime.parse(et, DTF_YMD_HMS);
            criteria = criteria.and("createdAt").gte(stDateTime).lt(etDateTime);
        }
        if (orderCode != null) {
            criteria = criteria.and("orderCode").is(orderCode);
        }
        if (type != null) {
            switch (type) {
                case 1:
                    criteria = criteria.and("orderType").is("order").and("status").is(11);
                    break;
                case 2:
                    criteria = criteria.and("orderType").is("order").and("status").in(22, 28);
                    break;
                case 3:
                    criteria = criteria.and("orderType").is("zhengzai").and("status").is(11);
                    break;
                case 4:
                    criteria = criteria.and("orderType").is("zhengzai").and("status").in(22, 28);
                    break;
            }
        } else {
            criteria = criteria.and("status").in(
                    GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue(),
                    GoblinStatusConst.Status.ORDER_LOG_STATUS_22.getValue(),
                    GoblinStatusConst.Status.ORDER_LOG_STATUS_28.getValue()
            );
        }
        Query query = Query.query(criteria);
        query.skip(skipCount).limit(size).with(Sort.by(Sort.Order.desc("createdAt")));
        List<GoblinOrderLogVo> dataList = mongoTemplate.find(query, GoblinOrderLogVo.class, GoblinOrderLogVo.class.getSimpleName());
        //查询总数量
        Query countQuery = Query.query(criteria);
        countQuery.fields().include("spuId");
        List<GoblinOrderLogVo> countList = mongoTemplate.find(countQuery, GoblinOrderLogVo.class, GoblinOrderLogVo.class.getSimpleName());
        long total = countList.size();
        HashMap<String, Object> map = CollectionUtil.mapStringObject();
        map.put("data", dataList);
        map.put("total", total);
        return map;
    }

    //商品订单列表
    public HashMap<String, Object> storeOrderList(String storeId, Integer page, String orderCode, String cst, String cet, String expressContacts, String phone, Integer status) {
        //查询销量
        int size = 20;
        int skipCount = ((page - 1) * size);
        Criteria criteria = Criteria.where("storeId").is(storeId);
        if (cst != null && cet != null) {
            criteria = criteria.and("createdAt").gte(cst).lt(cet);
        }
        if (orderCode != null) {
            criteria = criteria.and("orderCode").is(orderCode);
        }
        if (phone != null) {
            criteria = criteria.and("userMobile").is(phone);
        }
        if (status != null) {
            criteria = criteria.and("status").is(status);
        }
        if (expressContacts != null) {
            criteria = criteria.and("orderAttrVo.expressContacts").is(expressContacts);
        }
        Query query = Query.query(criteria);
        query.with(Sort.by(Sort.Order.desc("createdAt")));
        query.skip(skipCount).limit(size);
        query.fields().include("orderCode").include("createdAt").include("payType").include("status").include("orderSkuVoIds").include("orderId").include("priceActual").include("priceExpress").include("marketId")
                .include("orderAttrVo.expressContacts").include("orderAttrVo.expressAddressDetail").include("orderAttrVo.expressAddress").include("orderAttrVo.expressPhone");
        List<GoblinStoreOrderVo> dataList = mongoTemplate.find(query, GoblinStoreOrderVo.class, GoblinStoreOrderVo.class.getSimpleName());
        //查询总数量
        Query countQuery = Query.query(criteria);
        countQuery.fields().include("orderCode");
        List<GoblinStoreOrderVo> countList = mongoTemplate.find(countQuery, GoblinStoreOrderVo.class, GoblinStoreOrderVo.class.getSimpleName());
        long total = countList.size();
        HashMap<String, Object> map = CollectionUtil.mapStringObject();
        map.put("data", dataList);
        map.put("total", total);
        return map;
    }

    //商品退款订单列表
    public HashMap<String, Object> storeBackOrderList(String storeId, Integer page, String orderBackCode, Integer type, String cst, String cet, String orderCode, String spuName, Integer status) {
        //查询销量
        int size = 20;
        int skipCount = ((page - 1) * size);
        Criteria criteria = Criteria.where("storeId").is(storeId);
        if (cst != null && cet != null) {
            criteria = criteria.and("createdAt").gte(cst).lt(cet);
        }
        if (orderCode != null) {
            criteria = criteria.and("orderCode").is(orderCode);
        }
        if (orderBackCode != null) {
            criteria = criteria.and("backCode").is(orderBackCode);
        }
        if (status != null) {
            criteria = criteria.and("status").is(status);
        }
        if (type != null) {
            criteria = criteria.and("type").is(type);
        }
        if (spuName != null) {
            criteria = criteria.and("backOrderSkuVos.spuName").regex(".*?\\" + spuName);
        }
        Query query = Query.query(criteria);
        query.skip(skipCount).limit(size).with(Sort.by(Sort.Order.desc("createdAt")));
        ;
        query.fields().include("backCode").include("orderCode").include("backOrderId").include("type").include("status").include("realBackPrice").include("createdAt")
                .include("backOrderSkuVos.spuName").include("backOrderSkuVos.skuName").include("backOrderSkuVos.spuPic").include("backOrderSkuVos.skuPic")
                .include("backOrderSkuVos.skuSpecs").include("backOrderSkuVos.skuId").include("backOrderSkuVos.spuId").include("backOrderSkuVos.orderSkuId")
                .include("backOrderSkuVos.refundPrice");
        List<GoblinBackOrderVo> dataList = mongoTemplate.find(query, GoblinBackOrderVo.class, GoblinBackOrderVo.class.getSimpleName());
        //查询总数量
        Query countQuery = Query.query(criteria);
        countQuery.fields().include("orderCode");
        List<GoblinBackOrderVo> countList = mongoTemplate.find(countQuery, GoblinBackOrderVo.class, GoblinBackOrderVo.class.getSimpleName());
        long total = countList.size();
        HashMap<String, Object> map = CollectionUtil.mapStringObject();
        map.put("data", dataList);
        map.put("total", total);
        return map;
    }

    //商户 正在下单列表
    public List<GoblinStoreOrderVo> storeZhengzaiOrderList(int page, String storeId) {
        //查询销量
        int size = 40;
        int skipCount = ((page - 1) * size);
        Criteria criteria = Criteria.where("storeId").is(storeId).and("marketType").is(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue());
        Query query = Query.query(criteria);
        query.skip(skipCount).limit(size).with(Sort.by(Sort.Order.desc("createdAt")));
        return mongoTemplate.find(query, GoblinStoreOrderVo.class, GoblinStoreOrderVo.class.getSimpleName());
    }

    public List<GoblinFrontBanner> getListBanner() {
        Query query = Query.query(Criteria.where("delTag").is(0).and("bannerType").is(1));
        return mongoTemplate.find(query,
                GoblinFrontBanner.class, GoblinFrontBanner.class.getSimpleName());
    }

    public List<GoblinFrontBanner> getMiddleBanner() {
        Query query = Query.query(Criteria.where("delTag").is(0).and("bannerType").is(2));
        return mongoTemplate.find(query,
                GoblinFrontBanner.class, GoblinFrontBanner.class.getSimpleName());
    }

    public List<GoblinFrontHotWord> getHotWord() {
        Query query = Query.query(Criteria.where("delTag").is(0));
        return mongoTemplate.find(query,
                GoblinFrontHotWord.class, GoblinFrontHotWord.class.getSimpleName());
    }

    public List<GoblinFrontNavigation> getNavigation() {
        Query query = Query.query(Criteria.where("delTag").is(0));
        query.with(Sort.by(Sort.Order.asc("indexs")));
        return mongoTemplate.find(query,
                GoblinFrontNavigation.class, GoblinFrontNavigation.class.getSimpleName());
    }

    /* ---------------------------------------- 商铺活动:优惠券 ---------------------------------------- */

    public GoblinStoreCouponBasicVo setMgtStoreCouponBasicVo(GoblinStoreCouponBasicVo vo) {
        return mongoTemplate.insert(vo, GoblinStoreCouponBasicVo.class.getSimpleName());
    }

    public boolean updateMgtStoreCouponBasicVo(GoblinStoreCouponBasicVo vo) {
        return mongoTemplate.getCollection(GoblinStoreCouponBasicVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("storeCouponId").is(vo.getStoreCouponId()).and("delFlg").is("0")).getQueryObject(),
                ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
        ).getModifiedCount() > 0;
    }

    public boolean activityMgtStoreCouponBasicVo(String uid, LocalDateTime time, String state, List<String> storeCouponIds) {
        return mongoTemplate.getCollection(GoblinStoreCouponBasicVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("storeCouponId").in(storeCouponIds).and("delFlg").is("0")).getQueryObject(),
                Update.update("state", state).set("updatedBy", uid).set("updatedAt", time).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean updateMgtStoreCouponStock(String storeCouponId, int stock, String uid, LocalDateTime time) {
        return mongoTemplate.getCollection(GoblinStoreCouponBasicVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("storeCouponId").is(storeCouponId).and("delFlg").is("0")).getQueryObject(),
                Update.update("stock", stock).set("updatedBy", uid).set("updatedAt", time).getUpdateObject()
        ).getModifiedCount() > 0;
    }

    public boolean delMgtStoreCouponBasicVo(String storeCouponId, String uid, LocalDateTime time) {
        return mongoTemplate.updateFirst(
                Query.query(Criteria.where("storeCouponId").is(storeCouponId).and("delFlg").is("0")),
                Update.update("delFlg", "1").set("deletedBy", uid).set("deletedAt", time),
                GoblinStoreCouponBasicVo.class.getSimpleName()
        ).getModifiedCount() > 0;
    }

    public boolean delMgtStoreCouponBasicVos(List<String> storeCouponIds, String uid, LocalDateTime time) {
        return mongoTemplate.updateFirst(
                Query.query(Criteria.where("storeCouponId").in(storeCouponIds).and("delFlg").is("0")),
                Update.update("delFlg", "1").set("deletedBy", uid).set("deletedAt", time),
                GoblinStoreCouponBasicVo.class.getSimpleName()
        ).getModifiedCount() > 0;
    }

    public GoblinStoreCouponBasicVo getMgtStoreCouponBasicVo(String storeCouponId) {
        return mongoTemplate.findOne(
                Query.query(Criteria.where("storeCouponId").is(storeCouponId).and("delFlg").is("0")),
                GoblinStoreCouponBasicVo.class, GoblinStoreCouponBasicVo.class.getSimpleName()
        );
    }

    public GoblinStoreCouponVo getStoreCouponVo(String storeCouponId) {
        return mongoTemplate.findOne(
                Query.query(Criteria.where("storeCouponId").is(storeCouponId).and("delFlg").is("0")),
                GoblinStoreCouponVo.class, GoblinStoreCouponBasicVo.class.getSimpleName()
        );
    }

    public PagedResult<GoblinStoreMgtCouponListVo> getMgtStoreCouponListVos(GoblinStoreMgtCouponFilterParam filterParam) {
        Criteria criteria = Criteria.where("delFlg").is("0").and("storeId").is(filterParam.getStoreId());
        if (StringUtils.isNotBlank(filterParam.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + filterParam.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            criteria.and("title").regex(pattern);
        }
        if (StringUtils.isNotBlank(filterParam.getStoreCouponNo())) {
            criteria.and("storeCouponNo").is(filterParam.getStoreCouponNo());
        }
        if (StringUtils.isNotBlank(filterParam.getState())) {
            criteria.and("state").is(filterParam.getState());
        }
        if (StringUtils.isNotBlank(filterParam.getStartTime())) {
            LocalDateTime startTime = DateUtil.Formatter.yyyyMMddHHmmss.parse(filterParam.getStartTime());
            LocalDateTime startTimeBegin = startTime.withHour(0).withMinute(0).withSecond(0).withNano(0);

            criteria.and("startTime").gte(startTimeBegin);
        }
        if (StringUtils.isNotBlank(filterParam.getEndTime())) {
            LocalDateTime endTime = DateUtil.Formatter.yyyyMMddHHmmss.parse(filterParam.getEndTime());
            LocalDateTime endTimeEnd = endTime.withHour(23).withMinute(59).withSecond(59).withNano(999);

            criteria.and("endTime").lte(endTimeEnd);
        }
        if (StringUtils.isNotBlank(filterParam.getCreatedDt())) {
            LocalDateTime createdAtBegin = DateUtil.Formatter.yyyyMMddHHmmss.parse(filterParam.getCreatedDt() + " 00:00:00");
            LocalDateTime createdAtEnd = createdAtBegin.withHour(23).withMinute(59).withSecond(59).withNano(999);

            criteria.and("createdAt").gte(createdAtBegin).lte(createdAtEnd);
        }
        Query query = Query.query(criteria);

        long count = mongoTemplate.count(query, GoblinStoreCouponBasicVo.class.getSimpleName());

        PagedResult<GoblinStoreMgtCouponListVo> pagedResult = ObjectUtil.getGoblinStoreMgtCouponListVoPagedResult();
        if (count <= 0) return pagedResult;

        query.with(PageRequest.of(filterParam.getPageNum() - 1, filterParam.getPageSize()));
        query.with(Sort.by(Sort.Order.desc("createdAt")));

        List<GoblinStoreMgtCouponListVo> mgtCouponListVos = mongoTemplate.find(query, GoblinStoreMgtCouponListVo.class, GoblinStoreCouponBasicVo.class.getSimpleName());

        return pagedResult.setList(mgtCouponListVos).setTotal(count, filterParam.getPageSize());
    }

    public List<Document> aggregateMgtUserCoupon(List<String> storeCouponIds) {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.project("storeCouponId", "state", "receiveStock"),
                Aggregation.match(Criteria.where("storeCouponId").in(storeCouponIds).and("state").ne(2)),
                Aggregation.group("storeCouponId", "state").count().as("totalCount")
        );
        AggregationResults<Document> aggregationResults = mongoTemplate.aggregate(aggregation, GoblinUserCouponBasicVo.class.getSimpleName(), Document.class);
        return aggregationResults.getMappedResults();
    }

    //根据艺人标签和演出查询商品
    public List<GoblinGoodsInfoVo> getMusicTagPGoods(String musicTag, String performanceId) {
        Query query = Query.query(Criteria.where("artagVoList.tagName").is(musicTag)
                .and("delFlg").is("0").and("shelvesStatus").is("3"));
        return mongoTemplate.find(query,
                GoblinGoodsInfoVo.class,
                GoblinGoodsInfoVo.class.getSimpleName()
        );

    }

    //获取退款sku订单价格
    public BigDecimal getRefundOrderSkuVoPrice(String orderSkuId) {
        BigDecimal refundPrice = BigDecimal.ZERO;
        List<GoblinBackOrderVo> backOrderVos = mongoTemplate.find(Query.query(Criteria.where("backOrderSkuVos.orderSkuId").is(orderSkuId).and("status").nin(3, 5, 9)),
                GoblinBackOrderVo.class, GoblinBackOrderVo.class.getSimpleName());
        for (GoblinBackOrderVo vo : backOrderVos) {
            for (GoblinBackOrderSkuVo orderSkuVo : vo.getBackOrderSkuVos()) {
                refundPrice = refundPrice.add(orderSkuVo.getRefundPrice());
            }
        }
        return refundPrice;
    }

    ;
    /* ---------------------------------------- 商城:用户优惠券 ---------------------------------------- */

    public List<GoblinUserCouponVo> getUserCouponVos(String uid) {
        return mongoTemplate.find(Query.query(Criteria.where("uid").is(uid)),
                GoblinUserCouponVo.class, GoblinUserCouponBasicVo.class.getSimpleName());
    }

    public GoblinUserCouponBasicVo insertUserCouponVo(GoblinUserCouponBasicVo vo) {
        return mongoTemplate.insert(vo, GoblinUserCouponBasicVo.class.getSimpleName());
    }

    public Boolean changeCouponVos(String ucouponId, GoblinUserCouponVo vo) {
        return mongoTemplate.getCollection(GoblinUserCouponVo.class.getSimpleName())
                .updateOne(Query.query(Criteria.where("ucouponId").is(ucouponId)).getQueryObject(),
                        ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(vo))
                ).getModifiedCount() > 0;
    }

    /* ---------------------------------------- 我的藏品 ---------------------------------------- */

    /**
     * 盲盒开启后，直接从`我的藏品列表`中移除
     */
    public boolean updateUserDigitalArtworkVoByUnboxing(GoblinUserDigitalArtworkVo vo) {
        UpdateResult updateResult = mongoTemplate.getCollection(GoblinUserDigitalArtworkVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("artworkId").is(vo.getArtworkId()).and("state").ne(1)).getQueryObject(),
                Update.update("state", vo.getState())
                        .set("delFlg", vo.getDelFlg())
                        .set("openingAt", vo.getOpeningAt())
                        .set("updatedAt", vo.getUpdatedAt())
                        .set("deletedAt", vo.getDeletedAt())
                        .getUpdateObject()
        );
        return updateResult.getModifiedCount() > 0;
    }

    public boolean updateUserDigitalArtworkVoByChainTrade(GoblinUserDigitalArtworkVo vo) {
        UpdateResult updateResult = mongoTemplate.getCollection(GoblinUserDigitalArtworkVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("artworkId").is(vo.getArtworkId())).getQueryObject(),
                Update.update("editionSn", vo.getEditionSn())
                        .set("nftId", vo.getNftId())
                        .set("releaseTxhash", vo.getReleaseTxhash())
                        .set("releaseAt", vo.getReleaseAt())
                        .set("tradingTxhash", vo.getTradingTxhash())
                        .set("tradingAt", vo.getTradingAt())
                        .set("state", vo.getState())
                        .set("updatedAt", vo.getUpdatedAt())
                        .getUpdateObject()
        );
        return updateResult.getModifiedCount() > 0;
    }

    public List<String> getPageUserDigitalArtworkIds(String uid, Integer pageNum, Integer pageSize) {
        Criteria criteria = Criteria.where("delFlg").is("0").and("uid").is(uid);
        Query query = Query.query(criteria);

        PagedResult<GoblinUserDigitalArtworkVo> pagedResult = ObjectUtil.getGoblinUserDigitalArtworkVoPagedResult();
        query.with(PageRequest.of(pageNum - 1, pageSize)).with(Sort.by(Sort.Order.desc("createdAt")));

        query.fields().include("artworkId");
        List<GoblinUserDigitalArtworkVo> list = mongoTemplate.find(query, GoblinUserDigitalArtworkVo.class, GoblinUserDigitalArtworkVo.class.getSimpleName());
        return CollectionUtils.isEmpty(list) ? null : list.stream().map(GoblinUserDigitalArtworkVo::getArtworkId).collect(Collectors.toList());
    }

    /* ----------------------------------------  ---------------------------------------- */
    /* ----------------------------------------  ---------------------------------------- */
}
