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.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.GoblinStoreMgtGoodsListVo;
import com.liquidnet.service.goblin.dto.vo.*;
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;

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

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

    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 belong, String keyword) {
        Criteria criteria = Criteria.where("delFlg").is("0").and("tagBelong").is(belong);
        if (StringUtils.isNotBlank(keyword)) {
            criteria.and("tagName").regex("^.*" + keyword + ".*$");
        }
        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.andOperator(
                    Criteria.where("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 GoblinStoreInfoVo getStoreInfoVoByUid(String uid) {
        return mongoTemplate.findOne(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 boolean delGoodsInfoVo(String spuId) {
        return mongoTemplate.remove(Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0")),
                GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName()).getDeletedCount() > 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.toArray()).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 (StringUtils.isNotBlank(filterParam.getKeyword())) {
            Pattern pattern = Pattern.compile("^.*" + filterParam.getKeyword() + ".*$", Pattern.CASE_INSENSITIVE);
            criteria.andOperator(
                    Criteria.where("name").regex(pattern)
            );
        }
        if (StringUtils.isNotBlank(filterParam.getShelvesStatus())) {
            criteria.andOperator(Criteria.where("shelvesStatus").is(filterParam.getShelvesStatus()));
        }
        if (StringUtils.isNotBlank(filterParam.getCateFid())) {
            criteria.andOperator(Criteria.where("cateFid").is(filterParam.getCateFid()));
        }
        if (StringUtils.isNotBlank(filterParam.getCateSid())) {
            criteria.andOperator(Criteria.where("cateSid").is(filterParam.getCateSid()));
        }
        if (StringUtils.isNotBlank(filterParam.getCateTid())) {
            criteria.andOperator(Criteria.where("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.andOperator(Criteria.where("createdAt").gte(createdAtBegin).lte(createdAtEnd));
        }
        if (null != filterParam.getPriceGe()) {
            criteria.andOperator(Criteria.where("priceGe").gte(filterParam.getPriceGe()));
        }
        if (null != filterParam.getPriceLe()) {
            criteria.andOperator(Criteria.where("priceGe").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());
    }

    // 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());
    }

    // 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());
    }

    // SPU信息
    public GoblinGoodsInfoVo getGoodsInfoVo(String spuId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("spuId").is(spuId).and("delFlg").is("0").and("shelvesStatus").is("3").and("spuAppear").is("0")),
                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("name").is(name).and("delFlg").is("0")),
                GoblinGoodsInfoVo.class, 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 boolean updateGoodsInfoVoAppear(String storeId, String spuAppear, LocalDateTime time, String uid) {
        return mongoTemplate.getCollection(GoblinGoodsInfoVo.class.getSimpleName()).updateOne(
                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) {
        return mongoTemplate.updateMulti(Query.query(Criteria.where("storeId").is(storeId).and("spuId").in(spuIdList.toArray())),
                Update.update("shelvesStatus", shelvesFlg ? "3" : "1").set("shelvesAt", time).set("updatedBy", uid).set("updatedAt", time),
                GoblinGoodsInfoVo.class.getSimpleName()).getModifiedCount() > 0;
    }

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

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

    public boolean delGoodsSkuInfoVo(GoblinGoodsSkuInfoVo vo) {
        return mongoTemplate.getCollection(GoblinGoodsSkuInfoVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("skuId").is(vo.getSkuId()).and("delFlg").is("0")).getQueryObject(),
                Update.update("updatedBy", vo.getUpdatedBy()).set("updatedAt", vo.getUpdatedAt())
                        .set("deletedBy", vo.getDeletedBy()).set("deletedAt", vo.getDeletedAt()).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")),
                GoblinGoodsSkuInfoVo.class, GoblinGoodsSkuInfoVo.class.getSimpleName());
    }

    // 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;
    }

    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;
    }

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

    /**
     * 添加 商铺活动 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(GoblinStoreMarketVo.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);
    }

    //添加 操作日志
    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 String storeMoney(String storeId, String spuId) {
        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);
        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")
                            .first("skuPriceActual").as("skuPriceActual")
                            .sum("skuPriceActualBig").as("skuPriceActualBig"));
        } else {
            aggregation = Aggregation.newAggregation(
                    Aggregation.match(criteria),
                    Aggregation.group("storeId")
                            .first("storeId").as("storeId")
                            .first("skuPriceActual").as("skuPriceActual")
                            .sum("skuPriceActualBig").as("skuPriceActualBig"));
        }
        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);
        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 (spuName != null) {
            //根据spu名称查询spuId
            Query query = Query.query(Criteria.where("name").regex(".*?" + spuName + ".*").and("storeId").is(storeId));
            query.fields().include("spuId").include("name");
            spuIdAndName = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
            criteria = criteria.and("spuId").in(spuIdAndName.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList()));
        }
        if (st != null && et != null) {
            criteria = criteria.and("createdAt").gte(st).lt(et);
        }
        //查询聚合数据
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.skip(skipCount),
                Aggregation.limit(size),
                Aggregation.group("spuId")
                        .first("spuId").as("spuId")
                        .first("createdAt").as("createdAt")
                        .sum("skuPriceActual").as("skuPriceActual")
        );
        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());
        }
        //查询总数量
        Query countQuery = Query.query(criteria);
        countQuery.fields().include("spuId");
        List<GoblinOrderLogVo> countList = mongoTemplate.find(countQuery, GoblinOrderLogVo.class, GoblinOrderLogVo.class.getSimpleName());
        long total = countList.stream().map(GoblinOrderLogVo::getSpuId).distinct().collect(Collectors.toList()).size();
        //处理数据
        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("status").in(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue()).and("spuId").is(spuId);
        if (st != null && et != null) {
            criteria = criteria.and("createdAt").gte(st).lt(et);
        }
        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(1);
                    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(1);
                    break;
                case 4:
                    criteria = criteria.and("orderType").is("zhengzai").and("status").in(22, 28);
                    break;
            }
        }
        Query query = Query.query(criteria);
        query.skip(skipCount).limit(size);
        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.skip(skipCount).limit(size);
        query.fields().include("orderCode").include("createdAt").include("payType").include("status").include("orderSkuVoIds").include("orderId").include("priceActual").include("priceExpress")
                .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 (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);
        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");
        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());
    }
}
