package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.service.GoodsSkuService;
import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dos.SeckillApply;
import cn.lili.modules.promotion.entity.dto.search.PromotionGoodsSearchParams;
import cn.lili.modules.promotion.entity.dto.search.SeckillSearchParams;
import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum;
import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum;
import cn.lili.modules.promotion.mapper.PromotionGoodsMapper;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import cn.lili.modules.promotion.service.SeckillApplyService;
import cn.lili.modules.promotion.tools.PromotionTools;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 促销商品业务层实现
 *
 * @author Chopper
 * @since 2021/3/18 9:22 上午
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class PromotionGoodsServiceImpl extends ServiceImpl<PromotionGoodsMapper, PromotionGoods> implements PromotionGoodsService {

    private static final String SKU_ID_COLUMN = "sku_id";

    /**
     * Redis
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 秒杀活动申请
     */
    @Autowired
    private SeckillApplyService seckillApplyService;
    /**
     * 规格商品
     */
    @Autowired
    private GoodsSkuService goodsSkuService;

    @Override
    public List<PromotionGoods> findSkuValidPromotion(String skuId, String storeIds) {

        GoodsSku sku = goodsSkuService.getGoodsSkuByIdFromCache(skuId);
        if (sku == null) {
            return new ArrayList<>();
        }
        QueryWrapper<PromotionGoods> queryWrapper = new QueryWrapper<>();

        queryWrapper.and(i -> i.or(j -> j.eq(SKU_ID_COLUMN, skuId))
                .or(n -> n.eq("scope_type", PromotionsScopeTypeEnum.ALL.name()))
                .or(n -> n.and(k -> k.eq("scope_type", PromotionsScopeTypeEnum.PORTION_GOODS_CATEGORY.name())
                        .and(l -> l.like("scope_id", sku.getCategoryPath())))));
        queryWrapper.and(i -> i.or(PromotionTools.queryPromotionStatus(PromotionsStatusEnum.START)).or(PromotionTools.queryPromotionStatus(PromotionsStatusEnum.NEW)));
        queryWrapper.in("store_id", Arrays.asList(storeIds.split(",")));
        return this.list(queryWrapper);
    }

    @Override
    public IPage<PromotionGoods> pageFindAll(PromotionGoodsSearchParams searchParams, PageVO pageVo) {
        return this.page(PageUtil.initPage(pageVo), searchParams.queryWrapper());
    }

    /**
     * 获取促销商品信息
     *
     * @param searchParams 查询参数
     * @return 促销商品列表
     */
    @Override
    public List<PromotionGoods> listFindAll(PromotionGoodsSearchParams searchParams) {
        return this.list(searchParams.queryWrapper());
    }

    /**
     * 获取促销商品信息
     *
     * @param searchParams 查询参数
     * @return 促销商品信息
     */
    @Override
    public PromotionGoods getPromotionsGoods(PromotionGoodsSearchParams searchParams) {
        return this.getOne(searchParams.queryWrapper(), false);
    }

    /**
     * 获取当前有效时间特定促销类型的促销商品信息
     *
     * @param skuId          查询参数
     * @param promotionTypes 特定促销类型
     * @return 促销商品信息
     */
    @Override
    public PromotionGoods getValidPromotionsGoods(String skuId, List<String> promotionTypes) {
        QueryWrapper<PromotionGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SKU_ID_COLUMN, skuId);
        queryWrapper.in("promotion_type", promotionTypes);
        queryWrapper.and(PromotionTools.queryPromotionStatus(PromotionsStatusEnum.START));
        return this.getOne(queryWrapper, false);
    }

    /**
     * 获取当前有效时间特定促销类型的促销商品价格
     *
     * @param skuId          skuId
     * @param promotionTypes 特定促销类型
     * @return 促销商品价格
     */
    @Override
    public Double getValidPromotionsGoodsPrice(String skuId, List<String> promotionTypes) {
        QueryWrapper<PromotionGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SKU_ID_COLUMN, skuId);
        queryWrapper.in("promotion_type", promotionTypes);
        queryWrapper.and(PromotionTools.queryPromotionStatus(PromotionsStatusEnum.START));
        return this.baseMapper.selectPromotionsGoodsPrice(queryWrapper);
    }

    @Override
    public Integer findInnerOverlapPromotionGoods(String promotionType, String skuId, Date startTime, Date endTime, String promotionId) {
        if (promotionId != null) {
            return this.baseMapper.selectInnerOverlapPromotionGoodsWithout(promotionType, skuId, startTime, endTime, promotionId);
        } else {
            return this.baseMapper.selectInnerOverlapPromotionGoods(promotionType, skuId, startTime, endTime);
        }
    }

    /**
     * 获取促销活动商品库存
     *
     * @param typeEnum    促销商品类型
     * @param promotionId 促销活动id
     * @param skuId       商品skuId
     * @return 促销活动商品库存
     */
    @Override
    public Integer getPromotionGoodsStock(PromotionTypeEnum typeEnum, String promotionId, String skuId) {
        String promotionStockKey = PromotionGoodsService.getPromotionGoodsStockCacheKey(typeEnum, promotionId, skuId);
        String promotionGoodsStock = stringRedisTemplate.opsForValue().get(promotionStockKey);

        //库存如果不为空，则直接返回
        if (promotionGoodsStock != null && CharSequenceUtil.isNotEmpty(promotionGoodsStock)) {
            return Convert.toInt(promotionGoodsStock);
        }
        //如果为空
        else {
            //获取促销商品，如果不存在促销商品，则返回0
            PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
            searchParams.setPromotionType(typeEnum.name());
            searchParams.setPromotionId(promotionId);
            searchParams.setSkuId(skuId);
            PromotionGoods promotionGoods = this.getPromotionsGoods(searchParams);
            if (promotionGoods == null) {
                return 0;
            }
            //否则写入新的促销商品库存
            stringRedisTemplate.opsForValue().set(promotionStockKey, promotionGoods.getQuantity().toString());
            return promotionGoods.getQuantity();
        }
    }

    @Override
    public List<Integer> getPromotionGoodsStock(PromotionTypeEnum typeEnum, String promotionId, List<String> skuId) {
        PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
        searchParams.setPromotionType(typeEnum.name());
        searchParams.setPromotionId(promotionId);
        searchParams.setSkuIds(skuId);
        //获取促销商品，如果不存在促销商品，则返回0
        List<PromotionGoods> promotionGoods = this.listFindAll(searchParams);
        //接收数据
        List<Integer> result = new ArrayList<>(skuId.size());
        for (String sid : skuId) {
            Integer stock = null;
            for (PromotionGoods pg : promotionGoods) {
                if (sid.equals(pg.getSkuId())) {
                    stock = pg.getQuantity();
                }
            }
            //如果促销商品不存在，给一个默认值
            if (stock == null) {
                stock = 0;
            }
            result.add(stock);
        }
        return result;
    }

    /**
     * 更新促销活动商品库存
     *
     * @param typeEnum    促销商品类型
     * @param promotionId 促销活动id
     * @param skuId       商品skuId
     * @param quantity    更新后的库存数量
     */
    @Override
    public void updatePromotionGoodsStock(PromotionTypeEnum typeEnum, String promotionId, String skuId, Integer quantity) {
        String promotionStockKey = PromotionGoodsService.getPromotionGoodsStockCacheKey(typeEnum, promotionId, skuId);
        if (typeEnum.equals(PromotionTypeEnum.SECKILL)) {
            SeckillSearchParams searchParams = new SeckillSearchParams();
            searchParams.setSeckillId(promotionId);
            searchParams.setSkuId(skuId);
            SeckillApply seckillApply = this.seckillApplyService.getSeckillApply(searchParams);
            if (seckillApply == null) {
                throw new ServiceException(ResultCode.SECKILL_NOT_EXIST_ERROR);
            }
            seckillApplyService.updateSeckillApplyQuantity(promotionId, skuId, quantity);
        } else {
            LambdaUpdateWrapper<PromotionGoods> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(PromotionGoods::getPromotionType, typeEnum.name()).eq(PromotionGoods::getPromotionId, promotionId).eq(PromotionGoods::getSkuId, skuId);
            updateWrapper.set(PromotionGoods::getQuantity, quantity);
            this.update(updateWrapper);
        }

        stringRedisTemplate.opsForValue().set(promotionStockKey, quantity.toString());
    }

    /**
     * 更新促销活动商品库存
     *
     * @param promotionGoods 促销信息
     */
    @Override
    public void updatePromotionGoodsByPromotions(PromotionGoods promotionGoods) {
        LambdaQueryWrapper<PromotionGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PromotionGoods::getPromotionId, promotionGoods.getPromotionId());
        this.remove(queryWrapper);
        this.save(promotionGoods);
    }

    /**
     * 删除促销商品
     *
     * @param promotionId 促销活动id
     * @param skuIds      skuId
     */
    @Override
    public void deletePromotionGoods(String promotionId, List<String> skuIds) {
        LambdaQueryWrapper<PromotionGoods> queryWrapper = new LambdaQueryWrapper<PromotionGoods>()
                .eq(PromotionGoods::getPromotionId, promotionId).in(PromotionGoods::getSkuId, skuIds);
        this.remove(queryWrapper);
    }

    /**
     * 删除促销促销商品
     *
     * @param promotionIds 促销活动id
     */
    @Override
    public void deletePromotionGoods(List<String> promotionIds) {
        LambdaQueryWrapper<PromotionGoods> queryWrapper = new LambdaQueryWrapper<PromotionGoods>()
                .in(PromotionGoods::getPromotionId, promotionIds);
        this.remove(queryWrapper);
    }

    /**
     * 根据参数删除促销商品
     *
     * @param searchParams 查询参数
     */
    @Override
    public void deletePromotionGoods(PromotionGoodsSearchParams searchParams) {
        this.remove(searchParams.queryWrapper());
    }

}