package cn.iocoder.yudao.module.member.service.amount;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.member.controller.admin.business.vo.StatisticsVo;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoCardVO;
import cn.iocoder.yudao.module.member.dal.dataobject.card.CardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.money.MoneyDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.enums.CostTypeEnum;
import cn.iocoder.yudao.module.member.enums.GroupTypeEnum;
import cn.iocoder.yudao.module.member.enums.TimePeriodEnum;
import cn.iocoder.yudao.module.member.service.business.BusinessService;
import cn.iocoder.yudao.module.member.service.card.CardService;
import cn.iocoder.yudao.module.member.service.group.MemberGroupService;
import cn.iocoder.yudao.module.member.service.holiday.HolidayService;
import cn.iocoder.yudao.module.member.service.money.MoneyService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.member.util.MemberConstants;
import cn.iocoder.yudao.module.member.util.MemberTimeUtils;
import com.sun.istack.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.CASH_AMOUNT_NOT_ALLOW;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.CASH_AMOUNT_NOT_ENOUGH;
import static cn.iocoder.yudao.module.member.service.amount.LockManager.getUserLock;


/**
 * 餐盘统一扣款 Service 实现类
 *
 * @author 开发账号
 */

@Service
@Slf4j
public class DeductionServiceImpl implements DeductionService {

    @Resource
    private StringRedisTemplate deductionRedisTemplate;
    @Resource
    private CardService cardService;
    @Resource
    private MemberUserService userService;
    @Resource
    private BusinessService businessService;
    @Resource
    private MoneyService moneyService;
    @Resource
    private MemberGroupService memberGroupService;
    @Resource
    private HolidayService holidayService;


    private static final List<String> CHECK_LIST = Arrays.asList(CostTypeEnum.SHOPPING.getCode());

    @Override
    public void deduction(DishOrderDO dishOrderDO) {
        Long userId = dishOrderDO.getUserId();

        BigDecimal changeMoney;
        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;

        String name;
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            //新的总价
            String s = deductionRedisTemplate.opsForValue().get(dishOrderDO.getDiningPlatesNum() + "-" + dishOrderDO.getStoreId());
            BigDecimal total = new BigDecimal(StrUtil.isBlank(s) ? "0" : s);

            //计算减免价格
            BigDecimal reductionAmount = BigDecimal.ZERO;
            //补贴
            BigDecimal subsidyAmount = BigDecimal.ZERO;
            if (total.compareTo(BigDecimal.ZERO) > 0) {
                subsidyAmount = userService.getReductionAmount(userId, total, dishOrderDO.getCreateTime());
            }
            dishOrderDO.setSubsidyAmount(subsidyAmount);
            if (dishOrderDO.getReductionAmount().compareTo(BigDecimal.ZERO) > 0) {
                reductionAmount = reductionAmount.add(dishOrderDO.getReductionAmount());
                dishOrderDO.setReductionAmount(reductionAmount);
            } else {
                dishOrderDO.setReductionAmount(reductionAmount);
            }
            dishOrderDO.setReductionState(reductionAmount.compareTo(BigDecimal.ZERO) > 0 ? "1" : "0");
            //计算减免后的总价
            reductionAmount = reductionAmount.add(subsidyAmount);
            if (total.compareTo(reductionAmount) < 0) {
                total = BigDecimal.ZERO;
            } else {
                total = total.subtract(reductionAmount);
            }

            //微信
            BigDecimal wxAmount = user.getWxAmount();
            //现金
            BigDecimal cashAmount = user.getCashAmount();
            //当前金额
            BigDecimal money = user.getMoney();

            //待支付金额 最大退款金额
            dishOrderDO.setRefundAmount(total);
            if (money.compareTo(BigDecimal.ZERO) <= 0) {
                dishOrderDO.setPayAmount(total);
                dishOrderDO.setRefundAmount(BigDecimal.ZERO);
            } else {
                if (total.compareTo(money) > 0) {
                    dishOrderDO.setPayAmount(total.subtract(money));
                    dishOrderDO.setRefundAmount(money);
                }
            }
            //扣除金额
            user.setMoney(money.subtract(total));
            if (total.compareTo(money) > 0) {
                dishOrderDO.setOrderStatus(DishOrderDO.TOCOMPLETE);
                dishOrderDO.setWxAmount(wxAmount);
                dishOrderDO.setCashAmount(cashAmount);

                user.setWxAmount(BigDecimal.ZERO);
                user.setCashAmount(BigDecimal.ZERO);
            } else {
                dishOrderDO.setOrderStatus(DishOrderDO.COMPLETE);
                //扣除具体金额
                if (judge(userId)) { //微信->现金
                    if (total.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(total));
                        dishOrderDO.setWxAmount(total);
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        dishOrderDO.setWxAmount(wxAmount);
                        BigDecimal total1 = total.subtract(wxAmount);
                        user.setCashAmount(cashAmount.subtract(total1));
                        dishOrderDO.setCashAmount(total1);
                    }

                } else { //现金->微信
                    if (total.compareTo(cashAmount) <= 0) {
                        user.setCashAmount(cashAmount.subtract(total));
                        dishOrderDO.setCashAmount(total);
                    } else {
                        user.setCashAmount(BigDecimal.ZERO);
                        dishOrderDO.setCashAmount(cashAmount);
                        BigDecimal total1 = total.subtract(cashAmount);
                        user.setWxAmount(wxAmount.subtract(total1));
                        dishOrderDO.setWxAmount(total1);
                    }
                }
            }

            //修改
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            cashNewMoney = user.getCashAmount();
            changeMoney = total;
            newMoney = user.getMoney();
            name = user.getNickname();
        }

        //记录消费记录
        CardDO cardDO = new CardDO();
        cardDO.setType(TimePeriodEnum.getTimePeriod(dishOrderDO.getCreateTime()));
        cardDO.setUserId(userId);
        cardDO.setChangeMoney(changeMoney);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCarteenId(dishOrderDO.getStoreId());
        cardDO.setMoney(newMoney);

        cardService.insertOne(cardDO);

        dishOrderDO.setTotalMoney(changeMoney);
        dishOrderDO.setUpdateTime(LocalDateTime.now());
        deductionRedisTemplate.delete(dishOrderDO.getDiningPlatesNum() + "-" + dishOrderDO.getStoreId());

        //更新营业数据
        if (dishOrderDO.getOrderStatus().equals(DishOrderDO.COMPLETE)) {
            StatisticsVo statisticsVo = new StatisticsVo();
            statisticsVo.setCarteenId(dishOrderDO.getStoreId());
            statisticsVo.setTotalMoney(dishOrderDO.getTotalMoney());
            statisticsVo.setOrderSum(1);
            statisticsVo.setReduceMoney(dishOrderDO.getReductionAmount());
            statisticsVo.setTime(dishOrderDO.getCreateTime());
            statisticsVo.setOrderId(dishOrderDO.getId());
            statisticsVo.setSubsidyPurse(dishOrderDO.getSubsidyAmount());
            businessService.updateStatistics(statisticsVo);
        }

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void abnormalOrderHandle(DishOrderDO dishOrderDO) {
        String s = deductionRedisTemplate.opsForValue().get(dishOrderDO.getDiningPlatesNum() + "-" + dishOrderDO.getStoreId());
        dishOrderDO.setTotalMoney(new BigDecimal(StrUtil.isBlank(s) ? "0" : s));
        dishOrderDO.setUpdateTime(LocalDateTime.now());
        dishOrderDO.setOrderStatus(DishOrderDO.ABNORMAL);
        deductionRedisTemplate.delete(dishOrderDO.getDiningPlatesNum() + "-" + dishOrderDO.getStoreId());
    }

    @Override
    public void abnormalOrderDeduct(DishOrderDO dishOrderDO) {
        Long userId = dishOrderDO.getUserId();

        BigDecimal changeMoney;
        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;

        String name;
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            //新的总价
            BigDecimal total = dishOrderDO.getTotalMoney();

            //计算减免价格
            BigDecimal reductionAmount = BigDecimal.ZERO;
            //补贴
            BigDecimal subsidyAmount = BigDecimal.ZERO;
            if (total.compareTo(BigDecimal.ZERO) > 0) {
                subsidyAmount = userService.getReductionAmount(userId, total, dishOrderDO.getCreateTime());
            }
            dishOrderDO.setSubsidyAmount(subsidyAmount);
            if (dishOrderDO.getReductionAmount().compareTo(BigDecimal.ZERO) > 0) {
                reductionAmount = reductionAmount.add(dishOrderDO.getReductionAmount());
                dishOrderDO.setReductionAmount(reductionAmount);
            } else {
                dishOrderDO.setReductionAmount(reductionAmount);
            }
            dishOrderDO.setReductionState(reductionAmount.compareTo(BigDecimal.ZERO) > 0 ? "1" : "0");
            //计算减免后的总价
            reductionAmount = reductionAmount.add(subsidyAmount);
            if (total.compareTo(reductionAmount) < 0) {
                total = BigDecimal.ZERO;
            } else {
                total = total.subtract(reductionAmount);
            }

            //微信
            BigDecimal wxAmount = user.getWxAmount();
            //现金
            BigDecimal cashAmount = user.getCashAmount();
            //当前金额
            BigDecimal money = user.getMoney();

            //待支付金额 最大退款金额
            dishOrderDO.setRefundAmount(total);
            if (money.compareTo(BigDecimal.ZERO) <= 0) {
                dishOrderDO.setPayAmount(total);
                dishOrderDO.setRefundAmount(BigDecimal.ZERO);
            } else {
                if (total.compareTo(money) > 0) {
                    dishOrderDO.setPayAmount(total.subtract(money));
                    dishOrderDO.setRefundAmount(money);
                }
            }
            //扣除金额
            user.setMoney(money.subtract(total));
            if (total.compareTo(money) > 0) {
                dishOrderDO.setOrderStatus(DishOrderDO.TOCOMPLETE);
                dishOrderDO.setWxAmount(wxAmount);
                dishOrderDO.setCashAmount(cashAmount);

                user.setWxAmount(BigDecimal.ZERO);
                user.setCashAmount(BigDecimal.ZERO);
            } else {
                dishOrderDO.setOrderStatus(DishOrderDO.COMPLETE);
                //扣除具体金额
                if (judge(userId, MemberTimeUtils.Time2StringDate(dishOrderDO.getCreateTime()))) { //微信->现金
                    if (total.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(total));
                        dishOrderDO.setWxAmount(total);
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        dishOrderDO.setWxAmount(wxAmount);
                        BigDecimal total1 = total.subtract(wxAmount);
                        user.setCashAmount(cashAmount.subtract(total1));
                        dishOrderDO.setCashAmount(total1);
                    }

                } else { //现金->微信
                    if (total.compareTo(cashAmount) <= 0) {
                        user.setCashAmount(cashAmount.subtract(total));
                        dishOrderDO.setCashAmount(total);
                    } else {
                        user.setCashAmount(BigDecimal.ZERO);
                        dishOrderDO.setCashAmount(cashAmount);
                        BigDecimal total1 = total.subtract(cashAmount);
                        user.setWxAmount(wxAmount.subtract(total1));
                        dishOrderDO.setWxAmount(total1);
                    }
                }
            }

            //修改
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            cashNewMoney = user.getCashAmount();
            changeMoney = total;
            newMoney = user.getMoney();
            name = user.getNickname();
        }

        //记录消费记录
        CardDO cardDO = new CardDO();
        cardDO.setType(TimePeriodEnum.getTimePeriod(dishOrderDO.getCreateTime()));
        cardDO.setUserId(userId);
        cardDO.setChangeMoney(changeMoney);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCarteenId(dishOrderDO.getStoreId());
        cardDO.setMoney(newMoney);

        cardService.insertOne(cardDO);

        dishOrderDO.setTotalMoney(changeMoney);
        dishOrderDO.setUpdateTime(LocalDateTime.now());

        //更新营业数据
        if (dishOrderDO.getOrderStatus().equals(DishOrderDO.COMPLETE)) {
            StatisticsVo statisticsVo = new StatisticsVo();
            statisticsVo.setCarteenId(dishOrderDO.getStoreId());
            statisticsVo.setTotalMoney(dishOrderDO.getTotalMoney());
            statisticsVo.setOrderSum(1);
            statisticsVo.setReduceMoney(dishOrderDO.getReductionAmount());
            statisticsVo.setTime(dishOrderDO.getCreateTime());
            statisticsVo.setOrderId(dishOrderDO.getId());
            statisticsVo.setSubsidyPurse(dishOrderDO.getSubsidyAmount());
            businessService.updateStatistics(statisticsVo);
        }

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void orderTransferHandle(DishOrderDO dishOrderDO, Long transferUserId) {
        //退款处理
        if (dishOrderDO.getOrderStatus().equals(DishOrderDO.INCOMPLETE)) {
            dishOrderDO.setUserId(transferUserId);
        } else if (dishOrderDO.getOrderStatus().equals(DishOrderDO.COMPLETE)) {
            transferRefund(dishOrderDO);
            transferDeduct(dishOrderDO, transferUserId);
        } else if (dishOrderDO.getOrderStatus().equals(DishOrderDO.TOCOMPLETE)) {
            transferRefund(dishOrderDO);
            transferDeduct(dishOrderDO, transferUserId);
        }
    }

    void transferRefund(DishOrderDO dishOrderDO) {
        //退款
        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;
        String name;
        Long userId = dishOrderDO.getUserId();
        BigDecimal total = dishOrderDO.getTotalMoney().subtract(dishOrderDO.getPayAmount());
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            //用户当前金额
            BigDecimal userMoney = user.getMoney();
            BigDecimal cashAmount = user.getCashAmount();
            user.setCashAmount(cashAmount.add(total));
            user.setMoney(userMoney.add(total));
            userService.updateById(user);
            wxNewMoney = user.getWxAmount();
            newMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }
        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.ADD);
        cardDO.setChangeMoney(total);
        cardDO.setType(CostTypeEnum.REFUND.getCode());
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(dishOrderDO.getStoreId());
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        StatisticsVo statisticsVo = new StatisticsVo();
        statisticsVo.setCarteenId(dishOrderDO.getStoreId());
        statisticsVo.setTotalMoney(total.negate());
        statisticsVo.setOrderSum(-1);
        statisticsVo.setReduceMoney(dishOrderDO.getReductionAmount().negate());
        statisticsVo.setTime(dishOrderDO.getCreateTime());
        statisticsVo.setOrderId(dishOrderDO.getId());
        statisticsVo.setSubsidyPurse(dishOrderDO.getSubsidyAmount().negate());
        businessService.updateStatistics(statisticsVo);

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    void transferDeduct(DishOrderDO dishOrderDO, Long userId) {
        //扣款
        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;
        String name;
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            dishOrderDO.setUserId(userId);
            //新的总价
            BigDecimal total = dishOrderDO.getTotalMoney().add(dishOrderDO.getReductionAmount()).add(dishOrderDO.getSubsidyAmount());

            //计算减免价格
            BigDecimal reductionAmount = BigDecimal.ZERO;
            //补贴
            BigDecimal subsidyAmount = BigDecimal.ZERO;
            if (total.compareTo(BigDecimal.ZERO) > 0) {
                subsidyAmount = userService.getReductionAmount(userId, total, dishOrderDO.getCreateTime());
            }
            dishOrderDO.setSubsidyAmount(subsidyAmount);
            dishOrderDO.setReductionAmount(BigDecimal.ZERO);
            dishOrderDO.setReductionState(reductionAmount.compareTo(BigDecimal.ZERO) > 0 ? "1" : "0");
            //计算减免后的总价
            reductionAmount = reductionAmount.add(subsidyAmount);
            if (total.compareTo(reductionAmount) < 0) {
                total = BigDecimal.ZERO;
            } else {
                total = total.subtract(reductionAmount);
            }

            dishOrderDO.setTotalMoney(total);

            //微信
            BigDecimal wxAmount = user.getWxAmount();
            //现金
            BigDecimal cashAmount = user.getCashAmount();
            //当前金额
            BigDecimal money = user.getMoney();

            //待支付金额 最大退款金额
            dishOrderDO.setRefundAmount(total);
            if (money.compareTo(BigDecimal.ZERO) <= 0) {
                dishOrderDO.setPayAmount(total);
                dishOrderDO.setRefundAmount(BigDecimal.ZERO);
            } else {
                if (total.compareTo(money) > 0) {
                    dishOrderDO.setPayAmount(total.subtract(money));
                    dishOrderDO.setRefundAmount(money);
                }
            }
            //扣除金额
            user.setMoney(money.subtract(total));
            if (total.compareTo(money) > 0) {
                dishOrderDO.setOrderStatus(DishOrderDO.TOCOMPLETE);
                dishOrderDO.setWxAmount(wxAmount);
                dishOrderDO.setCashAmount(cashAmount);

                user.setWxAmount(BigDecimal.ZERO);
                user.setCashAmount(BigDecimal.ZERO);
            } else {
                dishOrderDO.setOrderStatus(DishOrderDO.COMPLETE);
                //扣除具体金额
                if (judge(userId, MemberTimeUtils.Time2StringDate(dishOrderDO.getCreateTime()))) { //微信->现金
                    if (total.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(total));
                        dishOrderDO.setWxAmount(total);
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        dishOrderDO.setWxAmount(wxAmount);
                        BigDecimal total1 = total.subtract(wxAmount);
                        user.setCashAmount(cashAmount.subtract(total1));
                        dishOrderDO.setCashAmount(total1);
                    }

                } else { //现金->微信
                    if (total.compareTo(cashAmount) <= 0) {
                        user.setCashAmount(cashAmount.subtract(total));
                        dishOrderDO.setCashAmount(total);
                    } else {
                        user.setCashAmount(BigDecimal.ZERO);
                        dishOrderDO.setCashAmount(cashAmount);
                        BigDecimal total1 = total.subtract(cashAmount);
                        user.setWxAmount(wxAmount.subtract(total1));
                        dishOrderDO.setWxAmount(total1);
                    }
                }
            }

            //修改
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            cashNewMoney = user.getCashAmount();
            newMoney = user.getMoney();
            name = user.getNickname();
        }

        //记录消费记录
        CardDO cardDO = new CardDO();
        cardDO.setType(TimePeriodEnum.getTimePeriod(dishOrderDO.getCreateTime()));
        cardDO.setUserId(userId);
        cardDO.setChangeMoney(dishOrderDO.getTotalMoney());
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCarteenId(dishOrderDO.getStoreId());
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        //更新营业数据
        if (dishOrderDO.getOrderStatus().equals(DishOrderDO.COMPLETE)) {
            StatisticsVo statisticsVo = new StatisticsVo();
            statisticsVo.setCarteenId(dishOrderDO.getStoreId());
            statisticsVo.setTotalMoney(dishOrderDO.getTotalMoney());
            statisticsVo.setOrderSum(1);
            statisticsVo.setReduceMoney(dishOrderDO.getReductionAmount());
            statisticsVo.setTime(dishOrderDO.getCreateTime());
            statisticsVo.setOrderId(dishOrderDO.getId());
            statisticsVo.setSubsidyPurse(dishOrderDO.getSubsidyAmount());
            businessService.updateStatistics(statisticsVo);
        }
        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void cashDraw(Long userId, BigDecimal money, String type, Long storeId) {

        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;
        String name;

        if (judgeDraw(userId)) {
            throw exception(CASH_AMOUNT_NOT_ALLOW);
        }

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            if (user.getCashAmount().compareTo(BigDecimal.ZERO) < 1
                    || money.compareTo(user.getCashAmount()) > 0) {
                throw exception(CASH_AMOUNT_NOT_ENOUGH);
            }
            user.setCashAmount(user.getCashAmount().subtract(money));
            user.setMoney(user.getMoney().subtract(money));
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            cashNewMoney = user.getCashAmount();
            newMoney = user.getMoney();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setChangeMoney(money);
        cardDO.setType(type);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(storeId);
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newMoney);
    }


    @Override
    public void wxDraw(Integer amount, Long userId) {

        BigDecimal wxNewMoney;
        BigDecimal cashNewMoney;
        BigDecimal newMoney;
        String name;
        BigDecimal changeMoney = new BigDecimal(amount).divide(new BigDecimal("100"));

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            user.setWxAmount(user.getWxAmount().subtract(changeMoney));
            user.setMoney(user.getMoney().subtract(changeMoney));
            userService.updateById(user);
            wxNewMoney = user.getWxAmount();
            newMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }


        //获取最新余额
        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setChangeMoney(changeMoney);
        cardDO.setType("7");
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void refund(Long userId, BigDecimal money, DishOrderDO dishOrderDO) {
        //获取最新余额
        BigDecimal wxNewMoney;
        BigDecimal newTotalMoney;
        BigDecimal cashNewMoney;
        String name;

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);

            //用户当前金额
            BigDecimal userMoney = user.getMoney();
            BigDecimal wxAmount = user.getWxAmount();
            BigDecimal cashAmount = user.getCashAmount();

            //订单消费金额
            BigDecimal dishWxAmount = dishOrderDO.getWxAmount();
            BigDecimal dishCashAmount = dishOrderDO.getCashAmount();

            BigDecimal newMoney = money;

            if (userMoney.compareTo(BigDecimal.ZERO) < 0) {
                newMoney = userMoney.add(newMoney);
            }

            if (newMoney.compareTo(BigDecimal.ZERO) < 0) {
                user.setWxAmount(BigDecimal.ZERO);
                user.setCashAmount(BigDecimal.ZERO);
                user.setMoney(newMoney);
            } else {
                if (newMoney.compareTo(dishCashAmount) <= 0) {
                    user.setCashAmount(cashAmount.add(newMoney));
                } else {
                    user.setCashAmount(cashAmount.add(dishCashAmount));
                    BigDecimal money2 = newMoney.subtract(dishCashAmount);
                    if (money2.compareTo(dishWxAmount) <= 0) {
                        user.setWxAmount(wxAmount.add(money2));
                    } else {
                        user.setWxAmount(wxAmount.add(dishWxAmount));
                    }

                }

            }
            userService.updateById(user);
            wxNewMoney = user.getWxAmount();
            newTotalMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.ADD);
        cardDO.setChangeMoney(money);
        cardDO.setType(CostTypeEnum.REFUND.getCode());
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(dishOrderDO.getStoreId());
        cardDO.setMoney(newTotalMoney);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newTotalMoney);
    }

    @Override
    public void reduction(Long userId, BigDecimal money, BigDecimal giftAmount, BigDecimal cashAmount, BigDecimal wxAmount, Long storeId) {

        BigDecimal newAmount;
        BigDecimal cashNewAmount;
        BigDecimal wxNewAmount;
        String name;

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);

            //考虑欠款的情况下 退还都直接退到现金，不退回微信
            BigDecimal oldAmount  = user.getMoney();
            user.setMoney(user.getMoney().add(money));
            newAmount = user.getMoney();

            if(oldAmount.compareTo(BigDecimal.ZERO) < 0){
                if(newAmount.compareTo(BigDecimal.ZERO) > 0){
                    user.setCashAmount(user.getCashAmount().add(newAmount));
                }
            }else {
                user.setCashAmount(user.getCashAmount().add(money));
            }

            userService.updateById(user);
            wxNewAmount = user.getWxAmount();
            cashNewAmount = user.getCashAmount();
            name = user.getNickname();
        }
        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.ADD);
        cardDO.setChangeMoney(money);
        cardDO.setType(CostTypeEnum.REFUND.getCode());
        cardDO.setWxAmount(wxNewAmount);
        cardDO.setCashAmount(cashNewAmount);
        cardDO.setCarteenId(storeId);
        cardDO.setMoney(newAmount);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newAmount);
    }

    @Override
    public BigDecimal storeDeduction(BigDecimal total, @NotNull Long userId, Long storeId) {

        BigDecimal wxNewMoney;
        BigDecimal newMoney;
        BigDecimal cashNewMoney;
        String name;
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);

            BigDecimal wxAmount = user.getWxAmount();
            BigDecimal cashAmount = user.getCashAmount();

            BigDecimal money = user.getMoney();
            BigDecimal judgeAmount;
            boolean judge = judgeShopping(userId);
            if (judge) {
                judgeAmount = wxAmount;
            } else {
                judgeAmount = money;
            }

            if (total.compareTo(judgeAmount) > 0) {
                return judgeAmount.subtract(total);
            }

            //扣除金额
            user.setMoney(money.subtract(total));
            if (judge) {
                user.setWxAmount(wxAmount.subtract(total));
            } else {
                if (total.compareTo(cashAmount) <= 0) {
                    user.setCashAmount(cashAmount.subtract(total));
                } else {
                    user.setCashAmount(BigDecimal.ZERO);
                    BigDecimal total1 = total.subtract(cashAmount);
                    user.setWxAmount(wxAmount.subtract(total1));
                }
            }

            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            newMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setChangeMoney(total);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setType(CostTypeEnum.SHOPPING.getCode());
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(storeId);
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);


        //更新redis
        updateRedis(userId, name, wxNewMoney);

        return newMoney;
    }


    public void updateRedis(Long userId, String name, BigDecimal newMoney) {
        //更新缓存
        String redisKey = "USER_" + userId;
        AppUserInfoCardVO appUserInfoCardVO = new AppUserInfoCardVO();
        appUserInfoCardVO.setName(name);
        appUserInfoCardVO.setMoney(newMoney);
        deductionRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(appUserInfoCardVO));
    }

    @Override
    public void deduct(Long userId, BigDecimal money, String type, Long storeId, String time) {

        BigDecimal wxNewMoney;
        BigDecimal newMoney;
        BigDecimal cashNewMoney;
        String name;

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            BigDecimal total = user.getMoney();
            user.setMoney(total.subtract(money));
            if (total.compareTo(money) < 0) {
                user.setWxAmount(BigDecimal.ZERO);
                user.setCashAmount(BigDecimal.ZERO);
            } else {
                BigDecimal wxAmount = user.getWxAmount();
                BigDecimal cashAmount = user.getCashAmount();
                //计算金额
                if (judge(userId, time)) {
                    if (money.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(money));
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        BigDecimal total1 = money.subtract(wxAmount);
                        user.setCashAmount(cashAmount.subtract(total1));
                    }
                } else {
                    if (money.compareTo(cashAmount) <= 0) {
                        user.setCashAmount(cashAmount.subtract(money));
                    } else {
                        user.setCashAmount(BigDecimal.ZERO);
                        BigDecimal total1 = money.subtract(cashAmount);
                        user.setWxAmount(wxAmount.subtract(total1));
                    }
                }
            }
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            newMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setChangeMoney(money);
        cardDO.setType(type);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(storeId);
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void spaceDeduct(Long userId, BigDecimal money, String type, Long storeId) {
        BigDecimal wxNewMoney;
        BigDecimal newMoney;
        BigDecimal cashNewMoney;
        String name;

        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            BigDecimal total = user.getMoney();
            if (total.compareTo(money) < 0) {
                throw exception(CASH_AMOUNT_NOT_ENOUGH);
            } else {

                BigDecimal wxAmount = user.getWxAmount();
                BigDecimal cashAmount = user.getCashAmount();
                user.setMoney(total.subtract(money));
                //计算金额
                if (judgeSpace(userId)) {
                    if (money.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(money));
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        BigDecimal total1 = money.subtract(wxAmount);
                        user.setCashAmount(cashAmount.subtract(total1));
                    }
                } else {
                    if (money.compareTo(cashAmount) <= 0) {
                        user.setCashAmount(cashAmount.subtract(money));
                    } else {
                        user.setCashAmount(BigDecimal.ZERO);
                        BigDecimal total1 = money.subtract(cashAmount);
                        user.setWxAmount(wxAmount.subtract(total1));
                    }
                }


            }
            userService.updateById(user);

            wxNewMoney = user.getWxAmount();
            newMoney = user.getMoney();
            cashNewMoney = user.getCashAmount();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setChangeMoney(money);
        cardDO.setType(type);
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setCarteenId(storeId);
        cardDO.setMoney(newMoney);
        cardService.insertOne(cardDO);

        //更新redis
        updateRedis(userId, name, newMoney);
    }

    @Override
    public void storeOfflineDeduction(BigDecimal total, Long userId, Long storeId) {
        BigDecimal wxNewMoney;
        BigDecimal giftNewMoney;
        BigDecimal cashNewMoney;
        String name;
        synchronized (getUserLock(userId)) {
            MemberUserDO user = userService.getUser(userId);
            MoneyDO moneyDO = moneyService.getMoney(userId, storeId);

            BigDecimal wxAmount = user.getWxAmount();
            BigDecimal giftAmount = user.getGiftAmount();
            BigDecimal cashAmount = moneyDO.getCashAmount();

            //计算金额
            if (total.compareTo(cashAmount) <= 0) {
                moneyDO.setCashAmount(cashAmount.subtract(total));
            } else {
                moneyDO.setCashAmount(BigDecimal.ZERO);
                BigDecimal total1 = total.subtract(cashAmount);
                if (total1.compareTo(giftAmount) <= 0) {
                    user.setGiftAmount(giftAmount.subtract(total1));
                } else {
                    user.setGiftAmount(BigDecimal.ZERO);
                    BigDecimal total2 = total1.subtract(giftAmount);

                    if (total2.compareTo(wxAmount) <= 0) {
                        user.setWxAmount(wxAmount.subtract(total2));
                    } else {
                        user.setWxAmount(BigDecimal.ZERO);
                        moneyDO.setDebtAmount(wxAmount.subtract(total2).add(moneyDO.getDebtAmount()));
                    }
                }
            }
            userService.updateById(user);
            moneyService.updateById(moneyDO);

            wxNewMoney = user.getWxAmount();
            giftNewMoney = user.getGiftAmount();
            cashNewMoney = moneyDO.getCashAmount();
            name = user.getNickname();
        }

        CardDO cardDO = new CardDO();
        cardDO.setUserId(userId);
        cardDO.setChangeMoney(total);
        cardDO.setFlag(CardDO.MINUS);
        cardDO.setType(CostTypeEnum.SHOPPING.getCode());
        cardDO.setWxAmount(wxNewMoney);
        cardDO.setCashAmount(cashNewMoney);
        cardDO.setGiftAmount(giftNewMoney);
        cardDO.setCarteenId(storeId);
        cardService.insertOne(cardDO);


        //更新redis
        updateRedis(userId, name, wxNewMoney);

    }

    /**
     * 判断食堂扣款顺序(true - 微信，false - 现金)
     */
    public boolean judge(Long userId) {
        if(!MemberConstants.LIMIT_SWITCH){
            return false;
        }
        //获取用户所在组分类
        List<Integer> types = memberGroupService.getGroupTypeListByUserId(userId);
        //查询今天是否假期
        Boolean isHoliday = holidayService.checkHoliday();
        return isHoliday && (types.contains(GroupTypeEnum.ADMINISTRATIVE.getCode()) || types.contains(GroupTypeEnum.DISTRICT.getCode()));
    }

    /**
     * 判断食堂扣款顺序(true - 微信，false - 现金)
     */
    public boolean judge(Long userId, String time) {
        if(!MemberConstants.LIMIT_SWITCH){
            return false;
        }
        //获取用户所在组分类
        List<Integer> types = memberGroupService.getGroupTypeListByUserId(userId);
        //查询今天是否假期
        Boolean isHoliday = holidayService.checkHoliday(time);
        return isHoliday && (types.contains(GroupTypeEnum.ADMINISTRATIVE.getCode()) || types.contains(GroupTypeEnum.DISTRICT.getCode()));
    }

    /**
     * 判断购物付款顺序(true - 微信，false - 现金)
     */
    public boolean judgeShopping(Long userId) {
        if(!MemberConstants.LIMIT_SWITCH){
            return false;
        }
        //获取用户所在组分类
        List<Integer> types = memberGroupService.getGroupTypeListByUserId(userId);
        return (types.contains(GroupTypeEnum.YCLH.getCode()) || types.contains(GroupTypeEnum.DISTRICT.getCode()));

    }

    /**
     * 判断太空舱付款顺序(true - 微信，false - 现金)
     */
    public boolean judgeSpace(Long userId) {
        if(!MemberConstants.LIMIT_SWITCH){
            return false;
        }
        //获取用户所在组分类
        List<Integer> types = memberGroupService.getGroupTypeListByUserId(userId);
        //查询今天是否假期
        Boolean isHoliday = holidayService.checkHoliday();
        //盈创力和不允许
        if (types.contains(GroupTypeEnum.YCLH.getCode())) {
            return true;
        }
        //行政服务中心只允许工作日
        return isHoliday && types.contains(GroupTypeEnum.ADMINISTRATIVE.getCode());
    }

    /**
     * 判断是否能提现(true - 不能，false - 能)
     */
    public boolean judgeDraw(Long userId) {
        if(!MemberConstants.LIMIT_SWITCH){
            return false;
        }
        //获取用户所在组分类
        List<Integer> types = memberGroupService.getGroupTypeListByUserId(userId);
        return types.contains(GroupTypeEnum.YCLH.getCode()) || types.contains(GroupTypeEnum.DISTRICT.getCode())
                || types.contains(GroupTypeEnum.ADMINISTRATIVE.getCode()) || types.contains(GroupTypeEnum.OTHER.getCode());

    }


}

