package org.springblade.payment.callback.trade;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.enums.AppConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.entity.PointBills;
import org.springblade.ldt.bills.service.IBillsService;
import org.springblade.ldt.bills.service.IPointBillsService;
import org.springblade.ldt.mall.entity.Mall;
import org.springblade.ldt.mall.service.IMallService;
import org.springblade.ldt.user.entity.LoginUser;
import org.springblade.ldt.user.entity.Member;
import org.springblade.ldt.user.entity.UserChannelPoint;
import org.springblade.ldt.user.service.ILoginUserService;
import org.springblade.ldt.user.service.IMemberService;
import org.springblade.ldt.user.service.IUserChannelPointService;
import org.springblade.payment.entity.SuccessParams;
import org.springblade.payment.event.MallSendPointEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * @author: lianghanqiang
 * @description: 商场赠送积分
 * @since: 9/28/21 -- 2:27 PM
 */
@Component
@AllArgsConstructor
@Slf4j
public class MallSendCallback {
	private IMemberService memberService;
	private IPointBillsService pointBillsService;
	private IUserChannelPointService userChannelPointService;
	private IMallService mallService;
	private ILoginUserService loginUserService;
	private IBillsService billsService;

	@EventListener
	public void handle(MallSendPointEvent mallSendPointEvent){
		SuccessParams successParams = mallSendPointEvent.getSuccessParams();
		String requestNo = successParams.getRes().getString("requestNo");
		PointBills pointBills = pointBillsService.getOne(new QueryWrapper<PointBills>().lambda().eq(PointBills::getRequestNo, requestNo));
		Mall mall = mallService.getById(pointBills.getPayId());
		LoginUser user = loginUserService.getById(pointBills.getReceiveId());
		Bills bills = billsService.getById(pointBills.getTradeNo());

		//回调已处理，忽略后续回调
		if (!Objects.equals(bills.getPayStatus(), AppConstant.BillPayStatus.待付款.name())){
			return;
		}

		//更新用户账户
		UserChannelPoint userChannelPoint = updateChannelAccount(mall, pointBills.getPrice(), user);
		//会员数据更新
		Member member = handleMallMember(pointBills, bills.getPrice());
		//更新商场数据
		mall.setBalance(mall.getBalance().subtract(pointBills.getPrice()));
		//更新用户数据
		user.setChannelPoint(user.getChannelPoint().add(pointBills.getPrice()));
		//更新赠送积分账单
		pointBills.setPayStatus(AppConstant.BillPayStatus.付款成功.name());

		//同步数据
		try {
			updateData(userChannelPoint,user,member,mall,pointBills);
		}catch (ServiceException e){
			pointBills.setBillsDesc(e.getMessage());
			pointBillsService.saveOrUpdate(pointBills);
		}

	}

	/**
	 * 	数据同步
	 * */
	@Transactional
	 void updateData(UserChannelPoint userChannelPoint,LoginUser user,Member member,Mall mall,PointBills pointBills) throws ServiceException {
		Assert.isTrue(userChannelPointService.saveOrUpdate(userChannelPoint),()->{throw new ServiceException("更新渠道积分账户异常！");});
		Assert.isTrue(loginUserService.saveOrUpdate(user),()->{throw new ServiceException("更新用户信息异常！");});
		Assert.isTrue(memberService.saveOrUpdate(member),()->{throw new ServiceException("更新会员信息异常！");});
		Assert.isTrue(mallService.saveOrUpdate(mall),()->{throw new ServiceException("更新商场信息异常！");});
		Assert.isTrue(pointBillsService.saveOrUpdate(pointBills),()->{throw new ServiceException("更新赠送积分账单信息异常！");});
	}

	/**
	 * 	商场会员管理
	 * @param sendBill
	 * @param payNum
	 * */
	private Member handleMallMember(PointBills sendBill,  BigDecimal payNum){
		Mall mall = mallService.getById(sendBill.getPayId());
		Assert.notNull(mall, "找不到商场信息");
		Long receiveId = sendBill.getReceiveId();
		LoginUser loginUser = loginUserService.getById(receiveId);
		Member member = memberService.getOne(new QueryWrapper<Member>()
			.lambda()
			.eq(Member::getType, AppConstant.PLATFORM.MALL.name())
			.eq(Member::getUserId, receiveId)
			.eq(Member::getShopId, sendBill.getPayId()));

		if(Objects.isNull(member)){
			member = new Member();
			member.setMallId(sendBill.getPayId());
			member.setUserId(receiveId);
			member.setPhone(loginUser.getPhone());
			member.setAvatar(loginUser.getAvatar());
			member.setNickName(loginUser.getNickName());
			member.setType(AppConstant.PLATFORM.MALL.name());
			member.setPointValue(BigDecimal.ZERO);
			member.setPointTotal(BigDecimal.ZERO);
			member.setPayTotal(BigDecimal.ZERO);
			member.setTenantId(mall.getTenantId());
		}

		BigDecimal pointNum = payNum.multiply(sendBill.getSendNum());

		member.setPayTotal(member.getPayTotal().add(payNum));
		member.setPointTotal(member.getPointTotal().add(pointNum));
		member.setPointValue(member.getPointValue().add(sendBill.getPrice()));

		return member;
	}


	/**
	 * 	修改渠道积分账户
	 *  @param mall
	 * @param sendPrice
	 * @param user*/
	private UserChannelPoint updateChannelAccount(Mall mall, BigDecimal sendPrice, LoginUser user){
		UserChannelPoint channelPoint = userChannelPointService.getOne(new QueryWrapper<UserChannelPoint>()
			.lambda()
			.eq(UserChannelPoint::getChannelId, mall.getId())
			.eq(UserChannelPoint::getUserId, user.getId()));

		if(Objects.isNull(channelPoint)){
			channelPoint = new UserChannelPoint();
			channelPoint.setChannelId(mall.getId());
			channelPoint.setUserId(user.getId());
			channelPoint.setTotalPoint(BigDecimal.ZERO);
			channelPoint.setAvailable(BigDecimal.ZERO);
			channelPoint.setChannelLogo(mall.getLogo());
			channelPoint.setChannelName(mall.getMallName());
			channelPoint.setPointRate(mall.getPointRate());
			channelPoint.setUsedPoint(BigDecimal.ZERO);
		}
		channelPoint.setAvailable(channelPoint.getAvailable().add(sendPrice));
		channelPoint.setTotalPoint(channelPoint.getTotalPoint().add(sendPrice));
		return channelPoint;
	}
}
