package com.qs.mp.channel.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.qs.mp.channel.domain.Channel;
import com.qs.mp.channel.domain.ChannelMoneyLog;
import com.qs.mp.channel.mapper.ChannelMoneyLogMapper;
import com.qs.mp.channel.service.IChannelMoneyLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qs.mp.channel.service.IChannelService;
import com.qs.mp.common.enums.ChannelMoneyEnum;
import com.qs.mp.common.enums.ErrorCodeEnum;
import com.qs.mp.common.exception.DataOperationException;
import com.qs.mp.common.exception.ServiceException;
import com.qs.mp.common.utils.LogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

/**
 * <p>
 * 渠道账户流水 服务实现类
 * </p>
 *
 * @author quanshu
 * @since 2022-03-02
 */
@Service
public class ChannelMoneyLogServiceImpl extends ServiceImpl<ChannelMoneyLogMapper, ChannelMoneyLog> implements IChannelMoneyLogService {

  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());

  @Autowired
  private IChannelService channelService;

  @Override
  @Transactional
  public boolean changeMoney(ChannelMoneyLog moneyLog) {
    //查询数据更新对象，用户做脏读乐观锁版本标识别
    Channel channel = channelService.getById(moneyLog.getChannelId());

    boolean income = checkIncome(moneyLog.getType());
    int logMoney = moneyLog.getLogMoney();
    int money = 0;
    if (!income) {
      //根据收支方向，将金额转负，方便统一计算
      int negativeVal = (~(moneyLog.getLogMoney() - 1));
      //判断账户余额是否大于支付金额
      if(channel.getMoney() < moneyLog.getLogMoney()){
        LogUtil.error(logger, "账户余额不足，支出失败,money:{0},logMoney:{1}", new Object[]{channel.getMoney(), moneyLog.getLogMoney()});
        throw new DataOperationException(ErrorCodeEnum.ERROR_CODE_1008);
      }
      money = channel.getMoney() + negativeVal;
      moneyLog.setMoney(money);
      moneyLog.setLogMoney(negativeVal);
      moneyLog.setIncomeExpense(ChannelMoneyEnum.EXPENSES);
    } else {
      money = channel.getMoney() + moneyLog.getLogMoney();
      moneyLog.setMoney(money);
      moneyLog.setIncomeExpense(ChannelMoneyEnum.INCOME);
    }
    LogUtil.info(logger, "channelId:{0}, money:{1}", new Object[]{channel.getChannelId() , channel.getMoney()});

    //1、更新渠道余额表
    boolean rtn = channelService.update(new LambdaUpdateWrapper<Channel>().set(Channel::getMoney, money)
        .set(ChannelMoneyEnum.WITHDRAW == moneyLog.getType() || ChannelMoneyEnum.WITHDRAW_FEE == moneyLog.getType(), Channel::getFrozenMoney, channel.getFrozenMoney() + logMoney)
        .set(ChannelMoneyEnum.WITHDRAW_BACK == moneyLog.getType(), Channel::getFrozenMoney, channel.getFrozenMoney() - logMoney)
        .eq(Channel::getChannelId, channel.getChannelId()).eq(Channel::getMoney, channel.getMoney()));
    Assert.isTrue(rtn, "渠道余额更新失败，channelId:" + channel.getChannelId());

    //2、增加余额流水记录
    boolean logret = save(moneyLog);
    if (!logret) {
      LogUtil.error(logger,"插入渠道账户流水.channelId : " + moneyLog.getChannelId()
          + "; money: " + moneyLog.getLogMoney());
      throw new ServiceException(ErrorCodeEnum.ERROR_CODE_1009);
    }
    return true;
  }

  private boolean checkIncome(ChannelMoneyEnum bizType){
    //判断收支类型是否符合预定义类型
    if(ChannelMoneyEnum.COMMISSION == bizType || ChannelMoneyEnum.COUPON == bizType || ChannelMoneyEnum.WITHDRAW_BACK == bizType){
      return true;
    }else if(ChannelMoneyEnum.WITHDRAW == bizType || ChannelMoneyEnum.WITHDRAW_FEE == bizType
    || ChannelMoneyEnum.PURCHASE == bizType ){
      return false;
    } else {
      throw new DataOperationException(ErrorCodeEnum.ERROR_CODE_1007);
    }
  }
}
