
package com.tmerclub.cloud.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.product.util.ProductLangUtil;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.i18n.I18nMessage;
import com.tmerclub.cloud.common.product.constant.SupplierDeliveryType;
import com.tmerclub.cloud.common.product.dto.SpuDTO;
import com.tmerclub.cloud.common.product.vo.*;
import com.tmerclub.cloud.common.util.Arith;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.product.dto.GiveawayDTO;
import com.tmerclub.cloud.product.dto.GiveawaySpuDTO;
import com.tmerclub.cloud.product.mapper.GiveawayMapper;
import com.tmerclub.cloud.product.mapper.SpuMapper;
import com.tmerclub.cloud.product.model.Giveaway;
import com.tmerclub.cloud.product.service.GiveawayService;
import com.tmerclub.cloud.product.service.GiveawaySpuService;
import com.tmerclub.cloud.product.service.SkuService;
import com.tmerclub.cloud.product.service.SkuStockService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 赠品表
 *
 * @author tmerclub
 * @date 2022-08-16 11:11:58
 */
@Service
public class GiveawayServiceImpl implements GiveawayService {

    @Autowired
    private GiveawayMapper giveawayMapper;
    @Autowired
    private GiveawaySpuService giveawaySpuService;
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SkuStockService skuStockService;

    @Override
    public PageVO<Giveaway> page(PageDTO pageDTO) {
        return PageUtil.doPage(pageDTO, () -> giveawayMapper.list());
    }

    @Override
    public GiveawayVO getBySpuId(Long spuId) {
        return giveawayMapper.getBySpuId(spuId);
    }

    @Override
    public PageVO<GiveawayVO> listByShopId(PageDTO pageDTO, GiveawayDTO giveawayDTO) {
        return PageUtil.doPage(pageDTO, () -> giveawayMapper.listByShopId(giveawayDTO, I18nMessage.getLang()));
    }

    @Override
    public GiveawayVO getGiveawayBySpuId(Long spuId) {
        return giveawaySpuService.getGiveawayBySpuId(spuId);
    }

    @Override
    public GiveawayVO getGiveawaySpuBySpuId(Long spuId) {
        GiveawayVO giveawayVO = giveawaySpuService.getGiveawayBySpuId(spuId);
        if (Objects.isNull(giveawayVO)) {
            return null;
        }
        long currentTimeMillis = System.currentTimeMillis();
        // 未到开始时间或已超过结束时间
        if (giveawayVO.getStartTime().getTime() > currentTimeMillis || giveawayVO.getEndTime().getTime() <= currentTimeMillis) {
            return null;
        }
        List<GiveawaySpuVO> giveawaySpuList = giveawayVO.getGiveawaySpus();
        List<GiveawaySpuVO> resGiveawaySpus = new ArrayList<>(Constant.INITIAL_CAPACITY);

        // ================== 插入赠品的spu和sku信息，且获取库存进行判断 ==================
        // 批量查询赠品的spu和sku、库存信息
        List<Long> spuIds = new ArrayList<>(giveawaySpuList.size());
        List<Long> skuIds = new ArrayList<>(giveawaySpuList.size());
        for (GiveawaySpuVO giveawaySpuVO : giveawaySpuList) {
            spuIds.add(giveawaySpuVO.getSpuId());
            skuIds.add(giveawaySpuVO.getSkuId());
        }
        List<SpuVO> spuList = spuMapper.listSpuBySpuIds(spuIds);
        ProductLangUtil.spuList(spuList);
        List<SkuVO> skuList = skuService.listSkuAndStockBySkuIds(skuIds);
        ProductLangUtil.skuList(skuList);
        Map<Long, SpuVO> spuMap = spuList.stream().collect(Collectors.toMap(SpuVO::getSpuId, s -> s));
        Map<Long, SkuVO> skuMap = skuList.stream().collect(Collectors.toMap(SkuVO::getSkuId, s -> s));
        Integer lang = I18nMessage.getLang();

        // 遍历赠品spu，插入spu和sku信息
        if (CollUtil.isNotEmpty(giveawaySpuList)) {
            giveawaySpuList.forEach(giveawaySpuVO -> {
                boolean flag = addSpuAndSkuInfoHandler(
                        giveawaySpuVO,
                        spuMap.get(giveawaySpuVO.getSpuId()),
                        skuMap.get(giveawaySpuVO.getSkuId()),
                        lang);
                if (flag) {
                    resGiveawaySpus.add(giveawaySpuVO);
                }
            });
        }
        giveawayVO.setGiveawaySpus(resGiveawaySpus);
        return giveawayVO;
    }

    @Override
    public GiveawayVO getByGiveawayId(Long giveawayId) {
        GiveawayVO giveawayVO = giveawayMapper.getByGiveawayId(giveawayId, I18nMessage.getLang());
        List<GiveawaySpuVO> giveawaySpuList = giveawaySpuService.getByGiveawayId(giveawayVO.getGiveawayId());
        giveawaySpuList.forEach(this::addSpuAndSkuInfo);
        giveawayVO.setGiveawaySpus(giveawaySpuList);
        return giveawayVO;
    }

    private void addSpuAndSkuInfo(GiveawaySpuVO giveawaySpuVO) {
        Integer lang = I18nMessage.getLang();
        SpuVO spuVO = spuMapper.getBySpuId(giveawaySpuVO.getSpuId());
        if (Objects.nonNull(spuVO)) {
            Map<Integer, String> spuNameMap = spuVO.getSpuLangList().stream().collect(Collectors.toMap(SpuLangVO::getLang, SpuLangVO::getSpuName));
            giveawaySpuVO.setSpuName(spuNameMap.get(lang));
            giveawaySpuVO.setPriceFee(spuVO.getPriceFee());
            SkuVO skuVO = skuService.getSkuBySkuId(giveawaySpuVO.getSkuId());
            if (Objects.nonNull(skuVO)) {
                Map<Integer, String> skuNameMap = skuVO.getSkuLangList().stream().collect(Collectors.toMap(SkuLangVO::getLang, SkuLangVO::getSkuName));
                giveawaySpuVO.setSkuName(skuNameMap.get(lang));
                giveawaySpuVO.setPriceFee(skuVO.getPriceFee());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(GiveawayDTO giveawayDTO) {
        this.checkGiveawayInfo(giveawayDTO);
        Giveaway giveaway = BeanUtil.map(giveawayDTO, Giveaway.class);
        giveaway.setStatus(1);
        giveaway.setCreateTime(new Date());
        giveaway.setUpdateTime(new Date());
        if (giveaway.getStartTime().getTime() > System.currentTimeMillis()) {
            giveaway.setStatus(2);
        }
        // 保存赠品信息
        giveawayMapper.save(giveaway);
        // 保存赠品赠送商品信息
        List<GiveawaySpuDTO> giveawaySpuList = giveawayDTO.getGiveawaySpus();
        giveawaySpuList.forEach(s -> s.setGiveawayId(giveaway.getGiveawayId()));
        giveawaySpuService.insertBatch(giveawaySpuList);
        //清除缓存
        giveawaySpuService.removeGiveawayCacheBySupId(giveaway.getSpuId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(GiveawayDTO giveawayDTO) {
        Date now = new Date();
        this.checkGiveawayInfo(giveawayDTO);
        GiveawayVO dbGiveaway = giveawayMapper.getByGiveawayId(giveawayDTO.getGiveawayId(), I18nMessage.getLang());
        dbGiveaway.setUpdateTime(new Date());
        if (Objects.equals(dbGiveaway.getStatus(), StatusEnum.DELETE.value())) {
            // 找不到赠品或赠品已被删除
            throw new LuckException("找不到赠品或赠品已被删除");
        }
        if (Objects.equals(dbGiveaway.getStatus(), StatusEnum.DISABLE.value())) {
            // 当前赠品已失效
            throw new LuckException("当前赠品已失效");
        }
        if (!Objects.equals(dbGiveaway.getShopId(), giveawayDTO.getShopId())) {
            // 店铺id不相等
            throw new LuckException("店铺id不相等");
        }
        giveawayDTO.setStatus(StatusEnum.ENABLE.value());
        giveawayDTO.setUpdateTime(now);
        List<Long> deleteGiveawaySpuIds = new ArrayList<>(Constant.INITIAL_CAPACITY);
        // 获取旧的赠送商品数据
        List<GiveawaySpuVO> giveawaySpuList = giveawaySpuService.getByGiveawayId(giveawayDTO.getGiveawayId());
        giveawaySpuList.forEach(s -> deleteGiveawaySpuIds.add(s.getGiveawaySpuId()));
        Giveaway giveaway = BeanUtil.map(giveawayDTO, Giveaway.class);
        if (giveaway.getStartTime().getTime() > System.currentTimeMillis()) {
            giveaway.setStatus(2);
        } else {
            giveaway.setStatus(1);
        }
        boolean giveawayUpdateCount = giveawayMapper.update(giveaway, StatusEnum.ENABLE.value(), 0);
//        if (giveawayUpdateCount < 1) {
//            throw new LuckException("赠品信息更新失败，请刷新后重试");
//        }

        // 删除旧的赠送商品数据
        giveawaySpuService.batchDeleteByIds(deleteGiveawaySpuIds);
        // 新增赠送商品数据
        giveawayDTO.getGiveawaySpus().forEach(s -> s.setGiveawayId(giveawayDTO.getGiveawayId()));
        giveawaySpuService.insertBatch(giveawayDTO.getGiveawaySpus());
        //清除赠品缓存
        giveawaySpuService.removeGiveawayCacheBySupId(giveaway.getSpuId());
        giveawaySpuService.removeGiveawayCacheBySupId(dbGiveaway.getSpuId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeStatus(Long giveawayId, Integer status) {
        StatusEnum statusEnum = StatusEnum.instance(status);
        if (Objects.isNull(statusEnum)) {
            return;
        }
        boolean giveawayUpdateRes = false;
        switch (statusEnum) {
            case DISABLE:
            case DELETE:
                GiveawayVO giveawayVO = giveawayMapper.getByGiveawayId(giveawayId, I18nMessage.getLang());
                if (Objects.isNull(giveawayVO) || Objects.equals(giveawayVO.getStatus(), StatusEnum.DELETE.value())) {
                    // 当前赠品已被删除
                    throw new LuckException("当前赠品已被删除");
                }
                giveawayVO.setStatus(status);
                Giveaway giveaway = BeanUtil.map(giveawayVO, Giveaway.class);
                giveawayUpdateRes = giveawayMapper.update(giveaway, StatusEnum.DELETE.value(), 1);
                //清除缓存
                giveawaySpuService.removeGiveawayCacheBySupId(giveaway.getSpuId());
                break;
            default:
                break;
        }
        if (giveawayUpdateRes) {
            boolean giveawaySpuUpdateRes = giveawaySpuService.updateStatus(giveawayId, status);
            if (!giveawaySpuUpdateRes) {
                throw new LuckException("删除失败,请刷新后重试");
            }
        }
    }

    private boolean addSpuAndSkuInfoHandler(GiveawaySpuVO giveawaySpuVO, SpuVO spuVO, SkuVO skuVO, Integer lang) {
        if (Objects.isNull(spuVO)) {
            return false;
        } else {
            giveawaySpuVO.setSpuName(spuVO.getName());
            giveawaySpuVO.setPriceFee(spuVO.getPriceFee());
            giveawaySpuVO.setSkuImgUrl(skuVO.getImgUrl());
            if (Objects.isNull(skuVO.getStock()) || skuVO.getStock() <= 0) {
                return false;
            } else {
                giveawaySpuVO.setSkuName(skuVO.getSkuName());
                giveawaySpuVO.setPriceFee(skuVO.getPriceFee());
                if (Objects.nonNull(skuVO.getImgUrl())) {
                    giveawaySpuVO.setMainImgUrl(skuVO.getImgUrl());
                }
                giveawaySpuVO.setPartyCode(skuVO.getPartyCode());
            }
        }
        return true;
    }


    /**
     * 检查赠品信息
     *
     * @param giveaway
     */
    private void checkGiveawayInfo(GiveawayDTO giveaway) {
        if (DateUtil.compare(giveaway.getStartTime(), giveaway.getEndTime()) > 0) {
            // 活动开始时间不能大于结束时间
            throw new LuckException("活动开始时间不能大于结束时间");
        }
        if (Objects.isNull(giveaway.getGiveawayId()) && DateUtil.compare(giveaway.getEndTime(), new Date()) < 0) {
            // 新增时活动结束时间不能小于当前时间
            throw new LuckException("新增时活动结束时间不能小于当前时间");
        }
        // 主商品
        SpuVO mainSpu = spuMapper.getBySpuId(giveaway.getSpuId());
        if (Objects.isNull(mainSpu) || !Objects.equals(mainSpu.getShopId(), giveaway.getShopId())) {
            // 商品找不到，或店铺id不相等
            throw new LuckException("商品找不到，或店铺id不相等");
        }
        if (Objects.equals(mainSpu.getStatus(), StatusEnum.DELETE.value())) {
            throw new LuckException(mainSpu.getName() + I18nMessage.getMessage("已被删除，请重新选择"));
        }
        int count;
        if (Objects.isNull(giveaway.getGiveawayId())) {
            count = giveawayMapper.count(giveaway.getSpuId(), null);
        } else {
            count = giveawayMapper.count(giveaway.getSpuId(), giveaway.getGiveawayId());
        }
        if (count > 0) {
            // 一个主商品不能设置多个赠品活动
            throw new LuckException("一个主商品不能设置多个赠品活动");
        }
        // 检查时间段是否冲突
        this.checkTimeIsRepeat(giveaway.getSpuId(), giveaway.getStartTime(), giveaway.getEndTime(), giveaway.getGiveawayId());
        Map<Long, SpuVO> spuMap = new HashMap<>(16);
        spuMap.put(mainSpu.getSpuId(), mainSpu);
        List<GiveawaySpuDTO> giveawaySpuList = giveaway.getGiveawaySpus();
        double totalRefundPrice = 0.0;
        // 赠送商品
        for (GiveawaySpuDTO giveawaySpuDTO : giveawaySpuList) {
            SpuVO spuVO = spuMap.getOrDefault(giveawaySpuDTO.getSpuId(), spuMapper.getBySpuId(giveawaySpuDTO.getSpuId()));
            if (Objects.isNull(spuVO) || !Objects.equals(spuVO.getShopId(), giveaway.getShopId())) {
                // 商品找不到，或店铺id不相等
                throw new LuckException("商品找不到，或店铺id不相等");
            }
            if (Objects.equals(spuVO.getStatus(), StatusEnum.DELETE.value())) {
                // 商品已被删除
                throw new LuckException(spuVO.getName() + I18nMessage.getMessage("商品已被删除"));
            }
            SkuVO skuVO = skuService.getSkuBySkuId(giveawaySpuDTO.getSkuId());
            if (Objects.isNull(skuVO) || !Objects.equals(skuVO.getSpuId(), spuVO.getSpuId())) {
                // sku找不到，或商品id不相等
                throw new LuckException("sku找不到，或商品id不相等");
            }
            if (Objects.equals(skuVO.getStatus(), -1)) {
                // 规格已被删除
                throw new LuckException(spuVO.getName() + I18nMessage.getMessage("规格已被删除") + skuVO.getSkuName() + I18nMessage.getMessage("已被删除，请重新选择"));
            }
            if (Objects.equals(skuVO.getStatus(), StatusEnum.DISABLE.value())) {
                // 规格已被禁用
                throw new LuckException(spuVO.getName() + I18nMessage.getMessage("规格已被禁用") + skuVO.getSkuName() + I18nMessage.getMessage("已被禁用，请重新选择"));
            }
            if (Objects.isNull(giveawaySpuDTO.getGiveawayNum()) || giveawaySpuDTO.getGiveawayNum() <= 0) {
                giveawaySpuDTO.setGiveawayNum(1);
            }
            if (Objects.isNull(giveawaySpuDTO.getRefundPrice()) || giveawaySpuDTO.getRefundPrice() < 0) {
                giveawaySpuDTO.setRefundPrice(0L);
            }
            totalRefundPrice = Arith.add(totalRefundPrice, Arith.mul(giveawaySpuDTO.getRefundPrice(), giveawaySpuDTO.getGiveawayNum()));
            spuMap.put(spuVO.getSpuId(), spuVO);
        }
        double totalmainSpuPrice = Arith.mul(mainSpu.getPriceFee(), giveaway.getBuyNum());
        if (totalmainSpuPrice < totalRefundPrice) {
            // 赠品的总售后价不能超过主商品价格
            throw new LuckException("赠品的总售后价不能超过主商品价格");
        }
    }

    /**
     * 检查时间段是否重复
     *
     * @param spuId
     * @param startTime
     * @param endTime
     */
    private void checkTimeIsRepeat(Long spuId, Date startTime, Date endTime, Long giveawayId) {
        List<GiveawayVO> dbGiveawayList = giveawayMapper.countList(spuId, giveawayId, StatusEnum.ENABLE.value());
        for (GiveawayVO giveawayVO : dbGiveawayList) {
            if (DateUtil.compare(startTime, giveawayVO.getEndTime()) > 0 || DateUtil.compare(endTime, giveawayVO.getStartTime()) < 0) {
                continue;
            }
            // 时间冲突，一个主商品同一时间不能设置多个赠品活动
            throw new LuckException(I18nMessage.getMessage("活动时间与赠品【") + giveawayVO.getName()
                    + I18nMessage.getMessage("】的时间发生冲突，一个主商品同一时间不能设置多个赠品活动，【")
                    + giveawayVO.getName() + I18nMessage.getMessage("】的活动时间为")
                    + DateUtil.formatDateTime(giveawayVO.getStartTime())
                    + I18nMessage.getMessage("至")
                    + DateUtil.formatDateTime(giveawayVO.getEndTime()));
        }
    }

    @Override
    public List<Giveaway> listUnEndButNeedEndActivity() {
        return giveawayMapper.listUnEndButNeedEndActivity();
    }

    @Override
    public void startGiveawayActivity() {
        List<Long> idList = giveawayMapper.listUnStartButNeedStartActivity();
        giveawayMapper.startGiveawayActivity();
        giveawaySpuService.removeGiveawayCacheBatch(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void changeSpuTypeByGiveawayActivityIdList(List<Giveaway> giveawayList) {
        // 失效赠品活动
        giveawayMapper.changeGiveawayActivityStatusByGiveawayIdList(giveawayList);
        List<Long> giveawayIdList = giveawayList.stream().map(Giveaway::getGiveawayId).collect(Collectors.toList());
        giveawaySpuService.changeGiveawayActivityStatusByGiveawayIdList(giveawayIdList);
        List<Long> spuIds = giveawayList.stream().map(Giveaway::getSpuId).collect(Collectors.toList());
        spuMapper.changeToNormalSpu(spuIds);
    }

    @Override
    public void checkGiveawaySpuPrice(SpuDTO spuDTO) {
        GiveawayVO giveawayVO = giveawaySpuService.getGiveawayBySpuId(spuDTO.getSpuId());
        List<GiveawaySpuVO> giveawaySpuVOList;
        HashSet<Long> giveawayIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        //供应商发货的赠品也要失效掉
        if (Objects.equals(spuDTO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
            giveawaySpuVOList = giveawaySpuService.getBySpuId(spuDTO.getSpuId());
            if (CollectionUtils.isNotEmpty(giveawaySpuVOList)) {
                giveawaySpuVOList.forEach(s -> giveawayIds.add(s.getGiveawayId()));
            }
        }
        if (Objects.nonNull(giveawayVO)) {
            //修改后的赠品金额
            long updatePrice = giveawayVO.getBuyNum() * spuDTO.getPriceFee();
            //赠品的累加金额
            List<GiveawaySpuVO> giveawaySpus = giveawayVO.getGiveawaySpus();
            long giveawaySpuPrice = 0L;
            for (GiveawaySpuVO giveawaySpuVO : giveawaySpus) {
                giveawaySpuPrice += giveawaySpuVO.getRefundPrice() * giveawaySpuVO.getGiveawayNum();
            }
            if (updatePrice < giveawaySpuPrice || Objects.equals(spuDTO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                giveawayIds.add(giveawayVO.getGiveawayId());
            }
        }
        for (Long giveawayId : giveawayIds) {
            //失效该活动
            changeStatus(giveawayId, 0);
        }
    }

    @Override
    public List<Long> listMainSpuIdByGiveawaySpuId(Long spuId) {
        return giveawayMapper.listMainSpuIdByGiveawaySpuId(spuId);
    }


}
