package co.yixiang.yshop.module.member.service.userlevelconfig;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.module.member.controller.admin.userlevelconfig.vo.*;
import co.yixiang.yshop.module.member.controller.admin.userlevelequityref.vo.UserLevelEquityRefExportReqVO;
import co.yixiang.yshop.module.member.controller.app.userlevel.vo.SettleLevelInfoVO;
import co.yixiang.yshop.module.member.controller.app.userlevel.vo.UserLevelInfoVO;
import co.yixiang.yshop.module.member.convert.userlevelconfig.UserLevelConfigConvert;
import co.yixiang.yshop.module.member.convert.userlevelequityref.UserLevelEquityRefConvert;
import co.yixiang.yshop.module.member.dal.dataobject.user.MemberUserDO;
import co.yixiang.yshop.module.member.dal.dataobject.userlevelconfig.UserLevelConfigDO;
import co.yixiang.yshop.module.member.dal.dataobject.userlevelequity.UserLevelEquityDO;
import co.yixiang.yshop.module.member.dal.dataobject.userlevelequityref.UserLevelEquityRefDO;
import co.yixiang.yshop.module.member.dal.mysql.userlevelconfig.UserLevelConfigMapper;
import co.yixiang.yshop.module.member.enums.BillDetailEnum;
import co.yixiang.yshop.module.member.enums.LevelEquityEnum;
import co.yixiang.yshop.module.member.service.user.UserService;
import co.yixiang.yshop.module.member.service.userbill.UserBillService;
import co.yixiang.yshop.module.member.service.userlevelequityref.UserLevelEquityRefService;
import co.yixiang.yshop.module.product.api.coupon.CouponApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.member.enums.BillDetailEnum.TYPE_11;
import static co.yixiang.yshop.module.member.enums.ErrorCodeConstants.USER_LEVEL_CONFIG_NOT_EXISTS;

/**
 * 会员等级配置 Service 实现类
 *
 * @author admin
 */
@Service
@Validated
@Slf4j
public class UserLevelConfigServiceImpl implements UserLevelConfigService {

    @Resource
    private UserLevelConfigMapper userLevelConfigMapper;
    @Resource
    @Lazy
    private UserService userService;
    @Resource
    private UserLevelEquityRefService userLevelEquityRefService;
    @Resource
    private CouponApi couponApi;
    @Resource
    private UserBillService userBillService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createUserLevelConfig(UserLevelConfigCreateReqVO createReqVO) {
        // 插入
        UserLevelConfigDO userLevelConfig = UserLevelConfigConvert.INSTANCE.convert(createReqVO);
        userLevelConfigMapper.insert(userLevelConfig);
        //新增等级权益绑定关系
        userLevelEquityRefService.saveData(userLevelConfig.getId(), createReqVO.getLevelEquityList(), true);
        // 返回
        return userLevelConfig.getId();
    }

    @Override
    public void updateUserLevelConfig(UserLevelConfigUpdateReqVO updateReqVO) {
        // 校验存在
        validateUserLevelConfigExists(updateReqVO.getId());
        // 更新
        UserLevelConfigDO updateObj = UserLevelConfigConvert.INSTANCE.convert(updateReqVO);
        //新增等级权益绑定关系
        userLevelEquityRefService.saveData(updateReqVO.getId(), updateReqVO.getLevelEquityList(), false);
        userLevelConfigMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserLevelConfig(Long id) {
        // 校验存在
        validateUserLevelConfigExists(id);
        // 删除
        userLevelConfigMapper.deleteById(id);
    }

    private void validateUserLevelConfigExists(Long id) {
        if (userLevelConfigMapper.selectById(id) == null) {
            throw exception(USER_LEVEL_CONFIG_NOT_EXISTS);
        }
    }

    @Override
    public UserLevelConfigDO getUserLevelConfig(Long id) {
        return userLevelConfigMapper.selectById(id);
    }

    @Override
    public List<UserLevelConfigDO> getUserLevelConfigList(Collection<Long> ids) {
        return userLevelConfigMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<UserLevelConfigDO> getUserLevelConfigPage(UserLevelConfigPageReqVO pageReqVO) {
        return userLevelConfigMapper.selectPage(pageReqVO);
    }

    @Override
    public List<UserLevelConfigDO> getUserLevelConfigList(UserLevelConfigExportReqVO exportReqVO) {
        return userLevelConfigMapper.selectList(exportReqVO);
    }

    @Override
    public UserLevelInfoVO levelInfo(Long loginUserId) {
        MemberUserDO user = userService.getUser(loginUserId);
        UserLevelConfigDO currentLevel = userLevelConfigMapper.selectById(user.getLevel());
        UserLevelInfoVO userLevelInfoVO = new UserLevelInfoVO();
        userLevelInfoVO.setCurrentLevel(currentLevel);
        //等级列表
        Integer level = Objects.isNull(currentLevel) ? 0 : currentLevel.getLevel();
        UserLevelConfigExportReqVO reqVO = new UserLevelConfigExportReqVO();
        reqVO.setStatus(Boolean.TRUE);
        List<UserLevelConfigDO> list = this.getUserLevelConfigList(reqVO);
        Optional<UserLevelConfigDO> nextLevelOpt = list.stream().filter(item -> item.getLevel() > level).findFirst();
        nextLevelOpt.ifPresent(nextLevel -> {
            userLevelInfoVO.setNextLevel(nextLevel);
            //升级所需成长值
            Integer needGrowthValue = nextLevel.getGrowthValue() - user.getGrowthValue();
            userLevelInfoVO.setNeedGrowthValue(needGrowthValue);
        });
        userLevelInfoVO.setCurrentGrowthValue(user.getGrowthValue());
        return userLevelInfoVO;
    }

    @Override
    public void upgradeLevel(Long userId) {
        MemberUserDO user = userService.getUser(userId);
        if (null == user) {
            return;
        }
        log.warn("用户:{}触发了升级", user.getId());

        Integer growthValue = user.getGrowthValue();
        //等级列表
        UserLevelConfigExportReqVO reqVO = new UserLevelConfigExportReqVO();
        reqVO.setStatus(Boolean.TRUE);
        List<UserLevelConfigDO> userLevelConfigList = this.getUserLevelConfigList(reqVO);
        //当前等级
        Integer currentLevel = userLevelConfigList.stream()
                .filter(item -> item.getId().equals(user.getLevel()))
                .findFirst()
                .map(UserLevelConfigDO::getLevel)
                .orElse(0);
        UserLevelConfigDO upgradeLevel = null;
        for (UserLevelConfigDO item : userLevelConfigList) {
            if (growthValue >= item.getGrowthValue()
                    && item.getLevel() > currentLevel) {
                upgradeLevel = item;
            }
        }
        if (ObjectUtil.isNotNull(upgradeLevel)) {
            MemberUserDO newUser = new MemberUserDO();
            newUser.setId(userId);
            newUser.setLevel(upgradeLevel.getId());
            userService.updateById(newUser);
            log.warn("用户:{}进行了升级,等级id:{}", userId, upgradeLevel.getId());
            // 增加等级权益 优惠券,积分
            grantLevelEquity(user, upgradeLevel.getId());
        }
    }

    /**
     * 发放会员权益
     *
     * @param userId  /
     * @param levelId /
     */
    private void grantLevelEquity(MemberUserDO user, Long levelId) {
        Long userId = user.getId();
        List<UserLevelEquityDO> equityList = this.getUserLevelEquityListByUserId(userId);
        //积分
        Optional<UserLevelEquityDO> integralEquityOpt = equityList.stream().filter(item -> LevelEquityEnum.INTEGRAL.getType().equals(item.getType())).findFirst();
        integralEquityOpt.ifPresent(equity -> {
            Long integral = equity.getEquityValue();
            if (Objects.nonNull(integral) && integral > 0L) {
                userService.addIntegral(userId, new BigDecimal(integral));
                //增加流水
                String type = "升级赠送积分";
                BigDecimal newIntegral = NumberUtil.add(user.getIntegral(), integral);
                userBillService.income(userId, type, BillDetailEnum.CATEGORY_2.getValue(),
                        TYPE_11.getValue(),
                        BigDecimal.valueOf(integral.doubleValue()),
                        BigDecimal.valueOf(newIntegral.doubleValue()),
                        type, null);
                log.warn("会员:{},升级:{},增加了积分:{}", userId, levelId, integral);
            }
        });
        //优惠券
        Optional<UserLevelEquityDO> couponEquityOpt = equityList.stream().filter(item -> LevelEquityEnum.COUPON.getType().equals(item.getType())).findFirst();
        couponEquityOpt.ifPresent(equity -> {
            Long couponId = equity.getEquityValue();
            if (Objects.nonNull(couponId)) {
                ThreadUtil.execute(() -> {
                    couponApi.receiveCoupon(couponId, userId);
                    log.warn("会员:{},升级:{},发放优惠券:{}", userId, levelId, equity.getEquityValue());
                });
            }
        });
    }

    @Override
    public UserLevelConfigRespVO getUserLevelConfigVO(Long id) {
        UserLevelConfigDO userLevelConfigDO = userLevelConfigMapper.selectById(id);
        UserLevelEquityRefExportReqVO reqVO = new UserLevelEquityRefExportReqVO();
        reqVO.setLevelId(id);
        List<UserLevelEquityRefDO> userLevelEquityRefList = userLevelEquityRefService.getUserLevelEquityRefList(reqVO);

        UserLevelConfigRespVO convert = UserLevelConfigConvert.INSTANCE.convert(userLevelConfigDO);
        convert.setLevelEquityList(UserLevelEquityRefConvert.INSTANCE.convertList(userLevelEquityRefList));
        return convert;
    }

    @Override
    public List<UserLevelEquityDO> getUserLevelEquityListByUserId(Long loginUserId) {
        MemberUserDO user = userService.getUser(loginUserId);
        Long levelId = user.getLevel();
        if (levelId == 0) {
            return ListUtil.empty();
        }
        return userLevelEquityRefService.getUserLevelEquityList(levelId);
    }

    @Override
    public SettleLevelInfoVO settleLevelInfo(Long loginUserId) {
        MemberUserDO user = userService.getUser(loginUserId);
        List<UserLevelEquityDO> list = this.getUserLevelEquityListByUserId(loginUserId);

        SettleLevelInfoVO vo = new SettleLevelInfoVO();
        Boolean freeShipping = list.stream().anyMatch(item -> LevelEquityEnum.FREE_SHIPPING.getType().equals(item.getType()));
        BigDecimal discount = list.stream().filter(item -> LevelEquityEnum.DISCOUNT.getType().equals(item.getType())).map(item -> new BigDecimal(item.getEquityValue())).findFirst().orElse(new BigDecimal("10"));
        vo.setFreeShipping(freeShipping);
        vo.setDiscount(discount);
        vo.setIsVip(Objects.nonNull(user.getLevel()) && user.getLevel() > 0);
        return vo;
    }

}
