
package com.tmerclub.cloud.search.listener;

import cn.hutool.core.collection.CollUtil;
import com.tmerclub.cloud.api.combo.feign.ComboFeignClient;
import com.tmerclub.cloud.api.group.feign.GroupFeignClient;
import com.tmerclub.cloud.api.live.feign.LiveFeignClient;
import com.tmerclub.cloud.api.multishop.feign.IndexImgFeignClient;
import com.tmerclub.cloud.api.product.dto.SupplierSpuUpdateDTO;
import com.tmerclub.cloud.api.product.feign.*;
import com.tmerclub.cloud.api.seckill.feign.SeckillFeignClient;
import com.tmerclub.cloud.api.user.feign.PopupFeignClient;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.GroupCacheNames;
import com.tmerclub.cloud.common.cache.constant.ProductCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.product.bo.EsProductBO;
import com.tmerclub.cloud.common.product.constant.SalesType;
import com.tmerclub.cloud.common.product.constant.SpuType;
import com.tmerclub.cloud.common.product.constant.SupplierSpuType;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.search.bo.SpuBO;
import com.tmerclub.cloud.search.canal.model.CanalBinLogResult;
import com.tmerclub.cloud.search.constant.EsIndexEnum;
import com.tmerclub.cloud.search.util.EsSearchUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author tmerclub
 * @date 2020/11/13
 */
@Component
public class SpuCanalListener extends BaseCanalBinlogEventThrowExceptionProcessor<SpuBO> {

    private static final Logger log = LoggerFactory.getLogger(SpuCanalListener.class);

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @DubboReference
    private ProductFeignClient productFeignClient;

    @DubboReference
    private SpuFeignClient spuFeignClient;

    @DubboReference
    private ComboFeignClient comboFeignClient;

    @DubboReference
    private GiveawayFeignClient giveawayFeignClient;

    @DubboReference
    private IndexImgFeignClient indexImgFeignClient;

    @DubboReference
    private GroupFeignClient groupFeignClient;

    @DubboReference
    private SeckillFeignClient seckillFeignClient;

    @DubboReference
    private LiveFeignClient liveFeignClient;

    @DubboReference
    private PopupFeignClient popupFeignClient;

    /**
     * 插入商品，此时插入es
     */
    @Override
    protected void processInsertInternal(CanalBinLogResult<SpuBO> result) {
        Long spuId = result.getPrimaryKey();
        ServerResponseEntity<EsProductBO> esProductResponse = productFeignClient.loadEsProductBO(spuId);
        if (!esProductResponse.isSuccess()) {
            log.error("商品id为：{}的商品数据异常！", spuId);
            return;
        }
        EsProductBO esProductBO = esProductResponse.getData();
        //为团购商品获取商品活动最低价对应的sku原价
        if (esProductBO.getSpuType() == 1) {
            //获取活动sku最低价
            Object priceFree = RedisUtil.get(CacheNames.GROUP_SPU_PRICE_FREE + esProductBO.getActivityId());
            if (!Objects.isNull(priceFree)) {
                esProductBO.setPriceFee(Long.valueOf(priceFree.toString()));
                //移除
                RedisUtil.del(CacheNames.GROUP_SPU_PRICE_FREE + esProductBO.getActivityId());
            }
        }
        EsSearchUtil.esSave(esProductBO.getSpuId(), EsIndexEnum.PRODUCT, esProductBO);
        removeCache(esProductBO);
    }

    /**
     * 更新商品，删除商品索引，再重新构建一个
     */
    @Override
    protected void processUpdateInternal(CanalBinLogResult<SpuBO> result) {
        SpuBO afterData = result.getAfterData();
        SpuBO beforeData = result.getBeforeData();
        this.handleStatusChange(afterData, beforeData.getStatus());
        if (!Objects.isNull(beforeData.getPriceFee())) {
            log.info("更新代销商品价格，spuId:{}", afterData.getSpuId());
            // 更新代销商品价格
            spuFeignClient.soldOutSpuBySpu(afterData.getSpuId(), afterData.getPriceFee(), afterData.getMarketPriceFee());
        }

        // 供应商品更新品牌或者排序时,需要同步更新代销商品的品牌或排序
        if (Objects.nonNull(beforeData.getBrandId()) || Objects.nonNull(beforeData.getSeq())) {
            Long brandId = -1L;
            Integer seq = -1;
            if (Objects.nonNull(beforeData.getBrandId())) {
                brandId = afterData.getBrandId();
            }
            if (Objects.nonNull(beforeData.getSeq())) {
                seq = afterData.getSeq();
            }
            spuFeignClient.syncUpdateCommissionSpuBrandOrSeq(brandId, seq, afterData.getSpuId());
        }
        // 删除数据
        DeleteRequest request = new DeleteRequest(EsIndexEnum.PRODUCT.value(), String.valueOf(result.getPrimaryKey()));
        try {
            DeleteResponse deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
            if (!Objects.isNull(beforeData.getStatus()) && Objects.equals(afterData.getSupplierSpuType(), SupplierSpuType.YES.value())) {
                Object skuDelete = RedisUtil.get(ProductCacheNames.SKU_STATUS_DELETE + afterData.getSpuId());
                if (Objects.isNull(skuDelete)) {
                    log.info("供应商商品状态改变时同步改变商家发布的供应商品，spuId:{}", afterData.getSpuId());
                    //供应商商品状态改变时同步改变商家发布的供应商品
                    spuFeignClient.supplierUpdateSpuStatus(afterData.getSpuId(), afterData.getStatus());
                }
            }
            // 更新代销商品状态
            this.supplierUpdateSkuStatus(afterData, beforeData);
            log.info(deleteResponse.toString());
            // 保存es商品信息,删除的商品也要存一下，装修接口使用
            this.processInsertInternal(result);
        } catch (IOException e) {
            log.error(e.toString());
            throw new LuckException("更新es信息异常", e);
        }
    }

    /**
     * 清除商品关联的缓存
     *
     * @param esProductBO
     */
    private void removeCache(EsProductBO esProductBO) {
        // keys不能使用Arrays.asList生成，Arrays.asList生成的ArrayList是内部类没有实现add方法
        List<String> keys = new ArrayList<>(Constant.INITIAL_CAPACITY);
        keys.add(CacheNames.SKU_WITH_ATTR_LIST_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(CacheNames.SPU_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(CacheNames.SPU_EXTENSION_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(CacheNames.SPU_DETAIL_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(CacheNames.SPU_ATTR_VALUE_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(CacheNames.SPU_ACTIVITY_KEY + CacheNames.UNION + esProductBO.getSpuId());
        keys.add(GroupCacheNames.GROUP_BY_SPU_KEY + CacheNames.UNION + esProductBO.getSpuId());
        if (CollUtil.isNotEmpty(esProductBO.getTagIds())) {
            keys.add(CacheNames.SPU_TAG_BY_SHOP + CacheNames.UNION + Constant.PLATFORM_SHOP_ID);
        }
        // 批量删除与商品关联的缓存信息
        RedisUtil.deleteBatch(keys);
    }

    /**
     * 商品状态发生改变时，需要处理的事件
     *
     * @param spuBO     修改后的商品数据
     * @param oldStatus 修改前的商品状态
     */
    private void handleStatusChange(SpuBO spuBO, Integer oldStatus) {
        // 状态没有发生改变或者不是变更未下线、下架、删除状态，则不进行处理
        if (Objects.isNull(oldStatus)) {
            return;
        }

        productFeignClient.handleStatusChange(spuBO.getSpuId());
        if (!StatusEnum.offlineStatus(spuBO.getStatus())) {
            return;
        }
        boolean isTrue = (Objects.equals(spuBO.getStatus(), StatusEnum.DISABLE.value()) || Objects.equals(spuBO.getStatus(), StatusEnum.OFFLINE.value()))
                && !Objects.equals(spuBO.getSpuType(), SpuType.SCORE.value());
        if (isTrue) {
            log.info("不是积分商品下架，处理相关活动: {}", spuBO.getSpuId());
            // 下架商品时如果商品在套餐活动中且为主商品则失效套餐活动,赠品同样
            comboFeignClient.offComboMainSpu(spuBO.getSpuId());
            giveawayFeignClient.changeGiveawayStatus(spuBO.getSpuId());
            if (!Objects.equals(SpuType.ACTIVE.value(), spuBO.getSpuType())) {
                // 失效拼团和秒杀活动
                groupFeignClient.updateGroupActivityStatus(spuBO.getSpuId());
                seckillFeignClient.offlineSeckillBySpuIds(Arrays.asList(spuBO.getSpuId()),true);
            }
            //切换轮播图
            indexImgFeignClient.udpateIndexImgBySpuId(spuBO.getSpuId(), spuBO.getShopId());
            // 直播活动
            liveFeignClient.deleteLiveRoomProd(spuBO.getSpuId());
            // 弹窗广告
            popupFeignClient.deletePopupProd(spuBO.getSpuId(), spuBO.getShopId());
        }
        giveawayFeignClient.changeGiveawaySpuStatus(spuBO.getSpuId());
        comboFeignClient.removeComboSpuCache(spuBO.getSpuId());

    }


    /**
     * 检查供应商sku状态是否改变，改变对代销商品进行下架
     */
    private void supplierUpdateSkuStatus(SpuBO afterData, SpuBO beforeData) {
        // 非供应商商品，不需要判断
        if (!Objects.equals(afterData.getSupplierSpuType(), SupplierSpuType.YES.value())) {
            return;
        }
        // 供应商是否修改商品相关信息
        Object spuUpdateInfo = RedisUtil.get(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + afterData.getSpuId());
        if (Objects.isNull(spuUpdateInfo)) {
            RedisUtil.del(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + afterData.getSpuId());
            return;
        }
        SupplierSpuUpdateDTO updateInfo = (SupplierSpuUpdateDTO) spuUpdateInfo;
        // 价格没变化，sku没变化，不进行下架
        if (!(updateInfo.isPriceUpdate() || updateInfo.isSkuUpdate())) {
            RedisUtil.del(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + afterData.getSpuId());
            return;
        }
        //供应商sku禁用状态是否改变
        Object enable = RedisUtil.get(ProductCacheNames.SKU_STATUS_ENABLE + afterData.getSpuId());
        Object skuDelete = RedisUtil.get(ProductCacheNames.SKU_STATUS_DELETE + afterData.getSpuId());
        if (Objects.isNull(enable)) {
            if (Objects.isNull(skuDelete)) {
                // 供应商变更了商品信息，下架手动设价的代销商品,商家自行发货的不下价
                log.info("下架手动设价的代销商品，spuId:{}", afterData.getSpuId());
                spuFeignClient.soldOutManualPriceCommissionSpu(afterData.getSpuId(), SalesType.MANUAL_OPERATION_PRICE.value(), 1);
            }
            RedisUtil.del(ProductCacheNames.SKU_STATUS_DELETE + afterData.getSpuId());
        } else {
            if (!Objects.isNull(enable)) {
                //sku启用，下架手动设价
                log.info("sku启用，下架手动设价，spuId:{}", afterData.getSpuId());
                spuFeignClient.soldOutManualPriceCommissionSpu(afterData.getSpuId(), SalesType.MANUAL_OPERATION_PRICE.value(), -1);
                RedisUtil.del(ProductCacheNames.SKU_STATUS_ENABLE + afterData.getSpuId());
            }
        }
        RedisUtil.del(ProductCacheNames.SKU_STATUS_DELETE + afterData.getSpuId());
        RedisUtil.del(ProductCacheNames.SUPPLIER_SPU_UPDATE_STATUS + afterData.getSpuId());
    }
}
