package com.liquidnet.client.admin.zhengzai.goblin.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.client.admin.zhengzai.goblin.service.IGoblinSelfTagService;
import com.liquidnet.common.cache.redis.util.AbstractRedisUtil;
import com.liquidnet.common.cache.redis.util.RedisDataSourceUtil;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSelfTagVo;
import com.liquidnet.service.goblin.entity.GoblinGoodsArtag;
import com.liquidnet.service.goblin.entity.GoblinGoodsTag;
import com.liquidnet.service.goblin.entity.GoblinSelfTag;
import com.liquidnet.service.goblin.mapper.GoblinGoodsArtagMapper;
import com.liquidnet.service.goblin.mapper.GoblinGoodsTagMapper;
import com.liquidnet.service.goblin.mapper.GoblinSelfTagMapper;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 平台商品标签 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-12-27
 */
@Slf4j
@Service
public class GoblinSelfTagServiceImpl extends ServiceImpl<GoblinSelfTagMapper, GoblinSelfTag> implements IGoblinSelfTagService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisDataSourceUtil redisDataSourceUtil;
    @Autowired
    private GoblinSelfTagMapper goblinSelfTagMapper;
    @Autowired
    private GoblinGoodsTagMapper goblinGoodsTagMapper;
    @Autowired
    private GoblinGoodsArtagMapper goblinGoodsArtagMapper;

    @Transactional
    @Override
    public boolean addSave(GoblinSelfTag selfTag) {
        if (this.save(selfTag)) {
            mongoTemplate.insert(GoblinSelfTagVo.getNew().copy(selfTag), GoblinSelfTagVo.class.getSimpleName());

            redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.BASIC_SELF_TAG);
            redisDataSourceUtil.getRedisGoblinUtil().del(GoblinRedisConst.BASIC_SELF_EXTAG);

            return true;
        }
        return false;
    }

    @Transactional
    @Override
    public boolean editSave(GoblinSelfTag selfTag) {
        LambdaUpdateWrapper<GoblinSelfTag> updateWrapper = Wrappers.lambdaUpdate(GoblinSelfTag.class);
        updateWrapper.eq(GoblinSelfTag::getTagId, selfTag.getTagId());
        updateWrapper.eq(GoblinSelfTag::getTagBelong, selfTag.getTagBelong());
        updateWrapper.eq(GoblinSelfTag::getDelFlg, "0");

        updateWrapper.set(GoblinSelfTag::getTagType, selfTag.getTagType());
        updateWrapper.set(GoblinSelfTag::getTagName, selfTag.getTagName());
        updateWrapper.set(GoblinSelfTag::getTagPic, selfTag.getTagPic());
        if (this.update(updateWrapper)) {
            AbstractRedisUtil redisGoblinUtil = redisDataSourceUtil.getRedisGoblinUtil();
            redisGoblinUtil.del(GoblinRedisConst.BASIC_SELF_TAG);
            redisGoblinUtil.del(GoblinRedisConst.BASIC_SELF_EXTAG);
            UpdateResult updateResult = mongoTemplate.getCollection(GoblinSelfTagVo.class.getSimpleName()).updateOne(
                    Query.query(Criteria.where("tagId").is(selfTag.getTagId()).and("tagBelong").is(selfTag.getTagBelong()).and("delFlg").is("0")).getQueryObject(),
                    Update.update("tagType", selfTag.getTagType()).set("tagName", selfTag.getTagName()).set("tagPic", selfTag.getTagPic()).getUpdateObject()
            );
            if (updateResult.getModifiedCount() <= 0) {
                log.error("店铺管理:标签管理:编辑:MDB更新失败[selfTag={}]", JsonUtils.toJson(selfTag));
                throw new LiquidnetServiceException();
            }
            log.info("店铺管理:标签管理:编辑[selfTag={},MONGO.UpdateResult={}]", JsonUtils.toJson(selfTag), JsonUtils.toJson(updateResult));

            try {
                boolean isTagFlg = selfTag.getTagBelong().equals("0");
                String subDocName = isTagFlg ? "tagVoList" : "extagVoList";
                Query query = Query.query(Criteria.where(subDocName.concat(".tagId")).is(selfTag.getTagId()));
                query.fields().include("spuId");
                List<GoblinGoodsInfoVo> matchedGoodsInfoVoList = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
                if (!CollectionUtils.isEmpty(matchedGoodsInfoVoList)) {
                    List<String> matchedSpuIdList = matchedGoodsInfoVoList.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
                    Update update = Update.update(subDocName.concat(".$.tagName"), selfTag.getTagName())
                            .set(subDocName.concat(".$.tagPic"), selfTag.getTagPic());
                    if (!isTagFlg) {
                        update.set(subDocName.concat(".$.tagType"), selfTag.getTagType());
                    }
                    UpdateResult updateRelateGoodsResult = mongoTemplate.updateMulti(Query.query(Criteria.where(subDocName.concat(".tagId")).is(selfTag.getTagId())),
                            update, GoblinGoodsInfoVo.class.getSimpleName());
                    log.info("店铺管理:标签管理:编辑:MDB更新关联商品[匹配={},更新={}]",
                            updateRelateGoodsResult.getMatchedCount(), updateRelateGoodsResult.getModifiedCount());
                    if (updateRelateGoodsResult.getModifiedCount() > 0) {
                        matchedSpuIdList.forEach(spuId -> {
                            redisGoblinUtil.del(GoblinRedisConst.BASIC_GOODS.concat(spuId));
                            redisGoblinUtil.del(GoblinRedisConst.BASIC_GOODS_UNSHELVES.concat(spuId));
                        });
                    }
                }
            } catch (Exception e) {
                log.error("店铺管理:标签管理:编辑:更新关联商品异常[selfTag={}]", JsonUtils.toJson(selfTag), e);
            }
            return true;
        }
        return false;
    }

    @Transactional
    @Override
    public boolean remove(Object[] tagIdArr, String tagBelong) {
        boolean rmvResultFlg = this.update(Wrappers.lambdaUpdate(GoblinSelfTag.class)
                .in(GoblinSelfTag::getTagId, tagIdArr)
                .eq(GoblinSelfTag::getTagBelong, tagBelong)
                .eq(GoblinSelfTag::getDelFlg, "0")
                .set(GoblinSelfTag::getDelFlg, "1")
        );

        if (rmvResultFlg) {
            AbstractRedisUtil redisGoblinUtil = redisDataSourceUtil.getRedisGoblinUtil();
            redisGoblinUtil.del(GoblinRedisConst.BASIC_SELF_TAG);
            redisGoblinUtil.del(GoblinRedisConst.BASIC_SELF_EXTAG);
            UpdateResult updateResult = mongoTemplate.updateMulti(Query.query(Criteria.where("tagId").in(tagIdArr).and("delFlg").is("0").and("tagBelong").is(tagBelong)),
                    Update.update("delFlg", "1"),
                    GoblinSelfTagVo.class.getSimpleName()
            );
            if (updateResult.getModifiedCount() <= 0) {
                log.error("店铺管理:标签管理:删除:MDB更新失败[tagBelong={},tagIdArr={}]", tagBelong, JsonUtils.toJson(tagIdArr));
                throw new LiquidnetServiceException();
            }
            log.info("店铺管理:标签管理:删除[tagIdArr={},tagBelong={},MONGO.UpdateResult={}]", JsonUtils.toJson(tagIdArr), tagBelong, JsonUtils.toJson(updateResult));

            try {
                int updateGoodsTagCount = -1, updateGoodsArtagCount = -1;
                GoblinGoodsTag updateGoodsTag = new GoblinGoodsTag();
                updateGoodsTag.setDelFlg("1");
                updateGoodsTagCount = goblinGoodsTagMapper.update(updateGoodsTag, Wrappers.lambdaUpdate(GoblinGoodsTag.class)
                        .in(GoblinGoodsTag::getTagId, tagIdArr).eq(GoblinGoodsTag::getTagBelong, tagBelong).eq(GoblinGoodsTag::getDelFlg, "0"));
//
                boolean isTagVoListFlg = tagBelong.equals("0");
                if (!isTagVoListFlg) {
                    GoblinGoodsArtag updateGoodsArtag = new GoblinGoodsArtag();
                    updateGoodsArtag.setDelFlg("1");
                    updateGoodsArtagCount = goblinGoodsArtagMapper.update(updateGoodsArtag, Wrappers.lambdaUpdate(GoblinGoodsArtag.class)
                            .in(GoblinGoodsArtag::getTagId, tagIdArr).eq(GoblinGoodsArtag::getTagBelong, tagBelong).eq(GoblinGoodsArtag::getDelFlg, "0"));
                }

                Query query = Query.query(isTagVoListFlg ? Criteria.where("tagVoList.tagId").in(tagIdArr) :
                        new Criteria().orOperator(Criteria.where("extagVoList.tagId").in(tagIdArr), Criteria.where("artagVoList.tagId").in(tagIdArr)));
                query.fields().include("spuId");
                List<GoblinGoodsInfoVo> matchedGoodsInfoVoList = mongoTemplate.find(query, GoblinGoodsInfoVo.class, GoblinGoodsInfoVo.class.getSimpleName());
                if (!CollectionUtils.isEmpty(matchedGoodsInfoVoList)) {
                    List<String> matchedSpuIdList = matchedGoodsInfoVoList.stream().map(GoblinGoodsInfoVo::getSpuId).collect(Collectors.toList());
                    Update update = isTagVoListFlg ? new Update().pull("tagVoList", Query.query(Criteria.where("tagId").in(tagIdArr))) :
                            new Update().pull("extagVoList", Query.query(Criteria.where("tagId").in(tagIdArr)))
                                    .pull("artagVoList", Query.query(Criteria.where("tagId").in(tagIdArr)));

                    UpdateResult updateRelateGoodsResult = mongoTemplate.updateMulti(Query.query(Criteria.where("spuId").in(matchedSpuIdList)),
                            update, GoblinGoodsInfoVo.class.getSimpleName());
                    log.info("店铺管理:标签管理:删除:MDB更新关联商品[匹配={},更新={},MYSQL更新:TAG={},ARTAG={}]",
                            updateRelateGoodsResult.getMatchedCount(), updateRelateGoodsResult.getModifiedCount(), updateGoodsTagCount, updateGoodsArtagCount);

                    if (updateRelateGoodsResult.getModifiedCount() > 0) {
                        matchedSpuIdList.forEach(spuId -> {
                            redisGoblinUtil.del(GoblinRedisConst.BASIC_GOODS.concat(spuId));
                            redisGoblinUtil.del(GoblinRedisConst.BASIC_GOODS_UNSHELVES.concat(spuId));
                        });
                    }
                }
            } catch (Exception e) {
                log.error("店铺管理:标签管理:删除:更新关联商品异常[tagBelong={},tagIdArr={}]", tagBelong, JsonUtils.toJson(tagIdArr), e);
            }
            return true;
        }
        return false;
    }

    @Override
    public List<GoblinSelfTag> countsForList(List<String> tagIds) {
        return goblinSelfTagMapper.countsForList(tagIds);
    }
}
