package org.springblade.payment.callback;


import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
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.common.enums.OrderType;
import org.springblade.common.enums.ResCode;
import org.springblade.common.enums.SystemConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.gateway.common_gateway.entity.BillSuccessEvent;
import org.springblade.ldt.bills.entity.BalanceBills;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.entity.PointBills;
import org.springblade.ldt.bills.service.IBalanceBillsService;
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.shop.entity.Shop;
import org.springblade.ldt.shop.service.IShopService;
import org.springblade.ldt.user.entity.LoginUser;
import org.springblade.ldt.user.entity.UserChannelPoint;
import org.springblade.ldt.user.service.ILoginUserService;
import org.springblade.ldt.user.service.IUserChannelPointService;
import org.springblade.payment.entity.PaymentVO;
import org.springblade.payment.entity.SuccessParams;
import org.springblade.payment.event.UserPayEvent;
import org.springblade.webSocket.WebSocketServer;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
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: 8/5/21 -- 3:01 PM
 */
@Component
@AllArgsConstructor
@Slf4j
public class UserPayCallback {

	private ILoginUserService loginUserService;
	private IBillsService billsService;
	private IPointBillsService pointBillsService;
	private IBalanceBillsService balanceBillsService;
	private IShopService shopService;
	private IMallService mallService;
	private IUserChannelPointService userChannelPointService;
	private WebSocketServer webSocketServer;
	private ApplicationEventPublisher applicationEventPublisher;


	@EventListener
	@Async
	@Transactional(rollbackFor = Exception.class)
	public void PaySuccess(UserPayEvent userPayEvent) {
		SuccessParams successParams = userPayEvent.getSuccessParams();
		PaymentVO paymentVO = PaymentVO.builder().isSuccess(Boolean.FALSE).msg("订单付款异常！").build();
		try {
			//获取对应交易的积分账单、余额账单、支付账单以及交易用户
			LoginUser user = loginUserService.getById(successParams.getUserId());
			Bills bills = successParams.getBills();
			PointBills pointBills = Objects.isNull(successParams.getPointBillsId()) ? null : pointBillsService.getById(successParams.getPointBillsId());
			BalanceBills balanceBills = Objects.isNull(successParams.getBalanceBillsId()) ? null : balanceBillsService.getById(successParams.getBalanceBillsId());

			//更新各个账单的状态
			if (!Objects.isNull(pointBills)) {
				Assert.isTrue(handlePointBills(pointBills, user, successParams.getChannelId()), () -> {
					throw new ServiceException(ResCode.USER_PAY_CALLBACK_ERROR);
				});
			}

			if (!Objects.isNull(balanceBills)) {
				Assert.isTrue(handleBalanceBills(balanceBills, user), () -> {
					throw new ServiceException(ResCode.USER_PAY_CALLBACK_ERROR);
				});
			}

			bills.setPaystatus(SystemConstant.BillPayStatus.付款成功.name());

			//更新订单信息
			Assert.isTrue(billsService.saveOrUpdate(bills), () -> {
				throw new ServiceException(ResCode.USER_PAY_CALLBACK_ERROR);
			});

			//修改用户积分余额
			Assert.isTrue(loginUserService.saveOrUpdate(user), () -> {
				throw new ServiceException(ResCode.USER_PAY_CALLBACK_ERROR);
			});

			//更新商家账户余额
			Assert.isTrue(updateShopBalance(bills, pointBills), () -> {
				throw new ServiceException(ResCode.USER_PAY_CALLBACK_ERROR);
			});


			//通知处理 赠送用户积分 代理费等
			applicationEventPublisher.publishEvent(new BillSuccessEvent(successParams));

			paymentVO.setIsSuccess(Boolean.TRUE);
			paymentVO.setMsg("交易成功！");
			paymentVO.setSuccessParams(successParams);

		} catch (Exception e) {
			log.error(e.getMessage());
			throw new ServiceException(ResCode.TRADE_ERROR);
		} finally {
			webSocketServer.sendInfo(
				AppConstant.SOCKET_PRE.SHOP.getName()+successParams.getShopId(),
				JSON.toJSONString(paymentVO)
			);
		}
	}


	/**
	 * 修改用户积分以及积分账单状态
	 */
	private boolean handlePointBills(PointBills pointBills, LoginUser user, Long channelId) {
		UserChannelPoint channelPoint = userChannelPointService.getById(channelId);
		channelPoint.setAvailable(channelPoint.getAvailable().subtract(pointBills.getPrice()));
		user.setChannelPoint(user.getChannelPoint().subtract(pointBills.getPrice()));
		pointBills.setStatus(SystemConstant.BillPayStatus.付款成功.name());
		return pointBillsService.saveOrUpdate(pointBills) && userChannelPointService.saveOrUpdate(channelPoint);
	}

	/**
	 * 修改用户账户余额以及余额账单状态
	 */
	private boolean handleBalanceBills(BalanceBills balanceBills, LoginUser user) {
		user.setBalance(user.getBalance().subtract(balanceBills.getPrice()));
		balanceBills.setStatus(SystemConstant.BillPayStatus.付款成功.name());
		return balanceBillsService.saveOrUpdate(balanceBills);
	}

	/**
	 * 修改支付账单状态
	 */
	private boolean handleBills(Bills bills, LoginUser user, PointBills pointBills, BalanceBills balanceBills) {
		//补充更新订单信息
		if (!Objects.isNull(pointBills)) {
			bills.setPointNum(pointBills.getPrice());
		}
		if (!Objects.isNull(balanceBills)) {
			bills.setBalanceNum(balanceBills.getPrice());
		}
		bills.setPaystatus(SystemConstant.BillPayStatus.付款成功.name());
		return billsService.saveOrUpdate(bills);
	}


	/**
	 * 商家账户余额更新
	 *
	 * @param bills
	 */
	private boolean updateShopBalance(Bills bills, PointBills pointBills) {
		Shop shop = null;
		if (!Objects.isNull(bills)) {
			shop = shopService.getById(bills.getReceiveId());
			shop.setBalance(shop.getBalance().add(bills.getPrice()));
		}
		if (!Objects.isNull(pointBills)) {
			shop = shopService.getById(pointBills.getReceiveId());
			shop.setCharge(shop.getCharge().add(pointBills.getPrice()));
		}
		return Objects.isNull(shop) ? true : shopService.saveOrUpdate(shop);
	}
}



