package org.springblade.yeePay.controller;

import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.annotation.AccessLimit;
import org.springblade.common.constant.SystemConstant;
import org.springblade.common.utils.IPUtils;
import org.springblade.common.utils.MoneyDesUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.guosen.bussiness.entity.Bussiness;
import org.springblade.modules.guosen.bussiness.entity.BussinessDebit;
import org.springblade.modules.guosen.bussiness.entity.BussinessDebitRequest;
import org.springblade.modules.guosen.bussiness.excel.WithdrawRequestExcel;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitRequestService;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitService;
import org.springblade.modules.guosen.bussiness.service.IBussinessService;
import org.springblade.modules.guosen.bussinessInfo.entity.BussinessInfo;
import org.springblade.modules.guosen.bussinessInfo.service.IBussinessInfoService;
import org.springblade.modules.guosen.bussinessRegisterRequest.entity.BussinessRegisterRequest;
import org.springblade.modules.guosen.bussinessRegisterRequest.service.IBussinessRegisterRequestService;
import org.springblade.modules.guosen.bussinessTransferOrder.entity.BussinessTransferOrder;
import org.springblade.modules.guosen.bussinessTransferOrder.service.IBussinessTransferOrderService;
import org.springblade.modules.guosen.bussinessuserinfo.entity.BussinessUserInfo;
import org.springblade.modules.guosen.bussinessuserinfo.service.IBussinessUserInfoService;
import org.springblade.modules.guosen.bussinessuserwithdraw.entity.BussinessUserWithdraw;
import org.springblade.modules.guosen.bussinessuserwithdraw.service.IBussinessUserWithdrawService;
import org.springblade.modules.guosen.debtDaliyStat.entity.BusinessDeptDaliyStat;
import org.springblade.modules.guosen.debtDaliyStat.service.IBusinessDeptDaliyStatService;
import org.springblade.modules.guosen.withdrawRecords.service.IWithdrawRecordsService;
import org.springblade.modules.system.service.IParamService;
import org.springblade.yeePay.common.YeePayConst;
import org.springblade.yeePay.entity.*;
import org.springblade.yeePay.service.BussinessPayService;
import org.springblade.yeePay.service.YeePayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created By lidexi in 2021/7/8
 **/
@RestController
@RequestMapping("/bussiness/pay")
@Api(tags = "商户代付接口")
@Slf4j
public class BussinessPayController {

	@Autowired
	YeePayService yeePayService;
	@Autowired
	IBussinessService bussinessService;
	@Autowired
	IWithdrawRecordsService withdrawRecordsService;
	@Autowired
	IBussinessDebitRequestService bussinessDebitRequestService;
	@Autowired
	IBussinessDebitService bussinessDebitService;
	@Autowired
	IBusinessDeptDaliyStatService businessDeptDailyStatService;
	@Autowired
	private IParamService paramService;
	@Autowired
	private BussinessPayService bussinessPayService;
	@Autowired
	private IBussinessTransferOrderService bussinessTransferOrderService;
	@Autowired
	private IBussinessUserInfoService userInfoService;
	@Autowired
	private IBussinessRegisterRequestService bussinessRegisterRequestService;
	@Autowired
	private IBussinessUserWithdrawService withdrawService;
	@Autowired
	private IBussinessInfoService bussinessInfoService;
	@Autowired
	private IBussinessTransferOrderService transferOrderService;

	/**
	 *	代付1.0：查询订单状态
	 * @param orderQueryDto
	 * */
	@PostMapping("/queryOrder")
	public R queryOrder(@RequestBody @Valid OrderQueryDto orderQueryDto){
		log.info("=======================订单状态查询=======================");
		String businessOrderId = orderQueryDto.getBussinessOrderId();
		//获取当前登录用户
		BladeUser user = AuthUtil.getUser();
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
				.eq(Bussiness::getAccountId, user.getUserId()).eq(Bussiness::getSecret, orderQueryDto.getSecret()));
		Assert.notNull(bussiness,"商户不存在");
		List<BussinessUserWithdraw> withdrawList = withdrawService.getByBussinessOrderId(bussiness.getId(), Func.toStrList(businessOrderId));
		List<JSONObject> queryList = withdrawList.stream().map(item -> {
			JSONObject data = new JSONObject();
			Integer withdrawStatus = item.getWithdrawStatus();
			//status: 1待确认、2已确认、3确认失败
			if (withdrawStatus.intValue() == SystemConstant.WithdrawOrderStatus.SUCCESS.getValue()) {
				data.put("status", 2);
			} else if (withdrawStatus.intValue() == SystemConstant.WithdrawOrderStatus.FAIL.getValue()) {
				data.put("status", 3);
			} else {
				data.put("status", 0);
			}
			data.put("bussinessOrderId", item.getBussinessOrderId());
			data.put("failReason", item.getFailReason());
			return data;
		}).collect(Collectors.toList());
		return R.data(queryList);

		/*
		*代付1.1版本
		String bussinessOrderId = bussinessDebitDTO.getBussinessOrderId();
		String secret = bussinessDebitDTO.getSecret();
		if(StringUtil.isBlank(bussinessOrderId)){
			return R.fail("商户订单号不能为空");
		}
		if(StringUtil.isBlank(secret)){
			return R.fail("商户密钥不能为空");
		}
		//获取当前登录用户
		BladeUser user = AuthUtil.getUser();
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
			.eq(Bussiness::getAccountId, user.getUserId()).eq(Bussiness::getSecret, secret));
		Assert.notNull(bussiness,"商户不存在");
		System.out.println("****************user"+user.toString());
		System.out.println("**********business"+bussiness.toString());
		BussinessDebit dbBussinessDebt = bussinessDebitService.getByBussinessOrderId(bussiness.getId(), bussinessOrderId);
		if(dbBussinessDebt == null){
			return R.fail("商户订单不存在");
		}else{
			JSONObject data = new JSONObject();
			data.put("status", dbBussinessDebt.getStatus()); //1待确认、2已确认、3确认失败
			data.put("bussinessOrderId", dbBussinessDebt.getBussinessOrderId());
			data.put("failReason", dbBussinessDebt.getFailReason());
			return R.data(data);
		}*/
	}

	/**
	 *  账户服务-付款下单
	 *	代付：交易到银行卡(单笔出款)
	 *  1、先从子商户转账到平台商户
	 *  2、再由平台商户代付出去
	 * @param payOrderDto 交易信息
	 * */
//	@PostMapping("/toCard")
	@AccessLimit(second = 2, maxCount = 1)
	public R payToCard(@RequestBody @Valid PayOrderDto payOrderDto, @RequestParam("secret") String secret, HttpServletRequest request){
		String maintain = paramService.getValue("maintain");
		if(StringUtil.isNotBlank(maintain)){
			if(maintain.equals("0")){ //进入维护时间
				return R.fail("系统维护时间为每天晚上22:00-凌晨07:00");
			}
		}
		BladeUser user = AuthUtil.getUser();
		if(user == null){
			return R.fail("账号不存在");
		}
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
				.eq(Bussiness::getAccountId, user.getUserId()).eq(Bussiness::getSecret,secret));
		if(bussiness == null){
			return R.fail("商户不存在");
		}
		if(bussiness.getRegisterStatus() == null || bussiness.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			log.error("=================代付请求前校验，商户未完成进件审核=================");
			return R.fail("请先完成商户进件审核");
		}
		if(BigDecimal.valueOf(payOrderDto.getOrderAmount()).compareTo(bussiness.getMaxLimit()) == 1){ //大于的时候返回1，等于返回0，小于返回-1
			log.error("=================代付请求前校验，提现金额不能超过商户每日限额=================");
			return R.fail("代付金额不能超过商户每日限额(限额 : 发起金额(不含手续费) = " + bussiness.getMaxLimit().toString() + ":" + String.valueOf(payOrderDto.getOrderAmount()) + ")");
		}else{
			//获取今日采购商已代付金额
			BusinessDeptDaliyStat todayStat = businessDeptDailyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDailyStatService.createTodayStat(bussiness.getId(), null);
			}else{
				BigDecimal todayAmount = todayStat.getStatAmount();
				if(todayAmount.add(new BigDecimal(payOrderDto.getOrderAmount())).compareTo(bussiness.getMaxLimit()) == 1){ //如果当日已分润金额+本次订单分润金额大于商户每日上限分润金额
					log.error("=================代付请求前校验，今日提现金额已超过商户每日限额=================");
					return R.fail("今日代付金额已超过商户每日限额");
				}
			}
		}
		BussinessInfo bussinessInfo = this.bussinessInfoService.getByBussinessId(bussiness.getId());
		//1、先发起一次子商户转账到平台商户
		R<BigDecimal> bussinessRemainR = bussinessService.queryBalance(bussiness.getMerchantNo());
		BigDecimal remain = bussinessRemainR.getData();
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		BigDecimal orderAmount = new BigDecimal(debitDecimalFormat.format(payOrderDto.getOrderAmount()));
		BigDecimal payFee = new BigDecimal(1.00);
		BigDecimal transferFee = new BigDecimal(1.00);
		BigDecimal transferAmount = orderAmount.add(payFee);
		//如果余额小于订单金额+代付手续费+转账手续费，则认为不可以发起代付
		if(remain.compareTo(transferAmount.add(transferFee)) == -1){
			return R.fail("商户余额不足，无法发起代付。");
		}
		//保存采购商单笔代付请求对象
		BussinessDebitRequest bussinessDebitRequest = new BussinessDebitRequest();
		bussinessDebitRequest.setBussinessId(bussiness.getId());
		bussinessDebitRequest.setOrderCount(1);//订单总笔数
		bussinessDebitRequest.setStatus(0);//0为易宝未回调状态
		boolean debitRequestSave = bussinessDebitRequestService.save(bussinessDebitRequest);
		if(debitRequestSave){
			BussinessDebit debit = new BussinessDebit();
			debit.setFee(new BigDecimal(1.00));
			debit.setPrice(orderAmount);
			debit.setType(SystemConstant.BussinessDebitType.COMMISSION.getValue());
			debit.setBankAccountType(payOrderDto.getBankAccountType());
			debit.setReceiverAccountName(payOrderDto.getReceiverAccountName());
			debit.setReceiverAccountNo(payOrderDto.getReceiverAccountNo());
			debit.setReceiverBankCode(payOrderDto.getReceiverBankCode());
			debit.setBussinessOrderId(payOrderDto.getBussinessOrderId());
			debit.setMethod(2);//表示api对接
			String debitFormat = debitDecimalFormat.format(payOrderDto.getOrderAmount());
			debit.setFreeze(debitFormat);
			debit.setRequestId(bussinessDebitRequest.getId());
			debit.setBussinessId(bussiness.getId());
			debit.setRequestIp(IPUtils.getIP(request));
			debit.setCurrentRemain(remain.toString());
			if(this.bussinessDebitService.save(debit)){
				BussinessTransferOrder bussinessTransferOrder = new BussinessTransferOrder();
				bussinessTransferOrder.setFromMerchantNo(bussiness.getMerchantNo());
				bussinessTransferOrder.setToMerchantNo(bussinessInfo.getParentMerchantNo());
				bussinessTransferOrder.setTransferUsage("采购");
				bussinessTransferOrder.setOrderAmount(transferAmount.toString());
				bussinessTransferOrder.setFeeChargeSide("OUTSIDE");
				bussinessTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
				bussinessTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_PAY.getValue());
				bussinessTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
				boolean transferSave = bussinessTransferOrderService.save(bussinessTransferOrder);
				if(transferSave){
					R transferResult = bussinessPayService.transferOrder(bussinessTransferOrder, bussinessInfo.getParentMerchantNo());
					if(transferResult.isSuccess()){
						debit.setTransferOrderId(bussinessTransferOrder.getId());
						bussinessDebitService.updateById(debit);
						return R.success("受理成功，请等待结果");
					}else{
						debit.setTransferOrderId(bussinessTransferOrder.getId());
						debit.setStatus(SystemConstant.BussinessDebitStatus.FAIL.getValue());
						debit.setFreeze("0.00");
						debit.setFailReason("代付失败");
						bussinessDebitService.updateById(debit);
						return R.fail("代付失败");
					}
				}else{
					log.error("====================代付前转账业务订单保存失败====================");
					log.error(JSONUtil.toJsonStr(bussinessTransferOrder));
					return R.fail("系统异常");
				}
			}else{
				log.error("====================代付前debit保存失败====================");
				log.error(JSONUtil.toJsonStr(bussinessDebitRequest));
				return R.fail("系统异常");
			}
		}else{
			log.error("====================代付前debitRequest保存失败====================");
			log.error(JSONUtil.toJsonStr(bussinessDebitRequest));
			return R.fail("系统异常");
		}
	}

	/**
	 *  开放给第三方的商户提现功能
	 *	1、进行小微用户进件
	 *  2、进件成功后，入驻商户转账金额到平台商户
	 *  3、转账成功后，平台商户转账到小微用户商户号下
	 *  4、转账成功后。小微用户发起提现下单
	 * @param payToUserDto 交易信息
	 * */
	@PostMapping("/payToUser")
	@AccessLimit(second = 2, maxCount = 10)
	public R payToUser(@RequestBody @Valid PayToUserDto payToUserDto, HttpServletRequest request){
		String maintain = paramService.getValue("maintain");
		if(StringUtil.isNotBlank(maintain)){
			if(maintain.equals("0")){ //进入维护时间
				return R.data(400, "FAIL", "系统维护时间为每天晚上22:00-凌晨07:00");
			}
		}
		BladeUser user = AuthUtil.getUser();
		if(user == null){
			return R.data(400, "FAIL", "账号不存在");
		}
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
				.eq(Bussiness::getAccountId, user.getUserId()).eq(Bussiness::getSecret, payToUserDto.getSecret()));
		if(bussiness == null){
			return R.data(400, "FAIL", "商户不存在");
		}
		if(bussiness.getRegisterStatus() == null || bussiness.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			log.error("=================代付请求前校验，商户未完成进件审核=================");
			return R.data(400, "FAIL", "请先完成商户进件审核");
		}
		if(BigDecimal.valueOf(payToUserDto.getOrderAmount()).compareTo(bussiness.getMaxLimit()) == 1){ //大于的时候返回1，等于返回0，小于返回-1
			log.error("=================代付请求前校验，提现金额不能超过商户每日限额=================");
			return R.data(400, "FAIL", "代付金额不能超过商户每日限额(限额 : 发起金额(不含手续费) = " + bussiness.getMaxLimit().toString() + ":" + payToUserDto.getOrderAmount() + ")");
		}else{
			//获取今日采购商已代付金额
			BusinessDeptDaliyStat todayStat = businessDeptDailyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDailyStatService.createTodayStat(bussiness.getId(), null);
			}else{
				BigDecimal todayAmount = todayStat.getStatAmount();
				if(todayAmount.add(new BigDecimal(payToUserDto.getOrderAmount())).compareTo(bussiness.getMaxLimit()) == 1){ //如果当日已分润金额+本次订单分润金额大于商户每日上限分润金额
					log.error("=================代付请求前校验，今日提现金额已超过商户每日限额=================");
					return R.data(400, "FAIL", "今日代付金额已超过商户每日限额");
				}
			}
		}
		//检查商户是否有足够余额进行代付
		String transferRate = paramService.getValue("yee_transfer_rate");
		String withdrawRate = paramService.getValue("yee_withdraw_rate");
		R<BigDecimal> bussinessRemainR = bussinessService.queryBalance(bussiness.getMerchantNo());
		BigDecimal remain = bussinessRemainR.getData();
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		BigDecimal orderAmount = new BigDecimal(debitDecimalFormat.format(payToUserDto.getOrderAmount()));
		BigDecimal transferFee = new BigDecimal(debitDecimalFormat.format(Double.parseDouble(transferRate)));
		BigDecimal withdrawFee = new BigDecimal(debitDecimalFormat.format(Double.parseDouble(withdrawRate)));
		BigDecimal transferAmount = orderAmount.add(transferFee).add(withdrawFee);
		//如果余额小于订单金额+代付手续费+转账手续费，则认为不可以发起代付
		if(remain.compareTo(transferAmount.add(transferFee)) == -1){
			return R.data(400, "FAIL", "商户余额不足，无法发起代付。");
		}

		BussinessUserInfo userInfoDTO = this.toUserInfo(payToUserDto, bussiness.getId());
		BussinessUserInfo dbUserInfo = userInfoService.getByNameCardBank(userInfoDTO);
		Bussiness parentBussiness = bussinessService.getById(bussiness.getParentBussinessId());
		userInfoDTO.setRateStrategyId(parentBussiness.getMicroRateStrategyId());
		userInfoDTO.setParentMerchantNo(parentBussiness.getMerchantNo());
		if(dbUserInfo == null){
			boolean save = this.userInfoService.save(userInfoDTO);
			if(save){
				//情况一：发起小微用户进件和创建提现订单
				R result = this.userRegisterAndCreateWithdraw(userInfoDTO, payToUserDto, IPUtils.getIP(request));
				return result;
			}else{
				return R.data(400, "FAIL", "代付失败(CODE:40003)");
			}
		}else{
			Integer registerStatus = dbUserInfo.getRegisterStatus();
			if(registerStatus != null && registerStatus.intValue() == SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
				//情况二：直接发起提现前第一次转账
				R<Long> transferResult = this.transferOrderToPlatform(dbUserInfo, bussiness.getMerchantNo(), transferAmount.toString(), payToUserDto, IPUtils.getIP(request));
				if(transferResult.getCode() == 200){
					return R.data("PROCESSING", "代付受理成功，请等待结果");
				}else{
					return R.data(400, "FAIL", "代付失败(CODE:FT)");
				}
			}else if(registerStatus != null && (registerStatus.intValue() == SystemConstant.BussinessRegisterStatus.SUBMIT_FAIL.getValue()
							|| registerStatus.intValue() == SystemConstant.BussinessRegisterStatus.FAIL.getValue()
							|| registerStatus.intValue() == SystemConstant.BussinessRegisterStatus.DOING.getValue())){
				userInfoDTO.setId(dbUserInfo.getId());
				userInfoDTO.setCreateTime(dbUserInfo.getCreateTime());
				BussinessUserInfo userInfo = BeanUtil.copyProperties(userInfoDTO, BussinessUserInfo.class);
				boolean update = this.userInfoService.updateById(userInfo);
				if(update){
					//情况三：同一个用户之前进件失败，修改了信息只有，现在重新发起一次代付，也是走情况一的录像
					R result = this.userRegisterAndCreateWithdraw(userInfoDTO, payToUserDto, IPUtils.getIP(request));
					return result;
				}else{
					return R.data(400, "FAIL", "代付失败(CODE:40004)");
				}
			}else{
				return R.data("PROCESSING", "代付受理成功，请等待结果");
			}
		}
	}

	/**
	 *  开放给第三方的商户提现功能
	 *	1、进行小微用户进件
	 *  2、进件成功后，入驻商户转账金额到平台商户
	 *  3、转账成功后，平台商户转账到小微用户商户号下
	 *  4、转账成功后。小微用户发起提现下单
	 * */
	@PostMapping("/import-payToUser-excel")
	public R importPayToUserList(MultipartFile file){
		String maintain = paramService.getValue("maintain");
		if(StringUtil.isNotBlank(maintain)){
			if(maintain.equals("0")){ //进入维护时间
				return R.fail("系统维护时间为每天晚上22:00-凌晨07:00");
			}
		}
		//将表格解析为list
		List<WithdrawRequestExcel> withdrawRequestExcelList = ExcelUtil.read(file,WithdrawRequestExcel.class);
		cn.hutool.core.lang.Assert.isFalse(withdrawRequestExcelList.size() == 0,"表格中无记录");
		String payBatchSize = paramService.getValue("payBatchSize");
		if(withdrawRequestExcelList.size() > Integer.valueOf(payBatchSize)){
			return R.fail("一次最多导入" + payBatchSize + "条记录, 当前导入数量为：" + withdrawRequestExcelList.size());
		}
		//获取当前采购商的可用余额
		BladeUser bladeUser = AuthUtil.getUser();
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
						.eq(Bussiness::getAccountId, bladeUser.getUserId()));
		cn.hutool.core.lang.Assert.notNull(bussiness,"当前登录用户不是采购商，无法执行此操作");
		if(bussiness.getRegisterStatus() == null || bussiness.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			log.error("=================代付请求前校验，商户未完成进件审核=================");
			return R.fail("请先完成商户进件审核");
		}
		//本次代付订单金额
		BigDecimal totalAmount = withdrawRequestExcelList.stream().map(
						withdrawRequestExcel -> BigDecimal.valueOf(withdrawRequestExcel.getOrderAmount())
		).reduce(BigDecimal.ZERO,BigDecimal::add);
		//检查采购商今日上限金额是否已超
		if(totalAmount.compareTo(bussiness.getMaxLimit()) == 1){ //大于的时候返回1，等于返回0，小于返回-1
			log.error("=================代付请求前校验，提现金额不能超过商户每日限额=================");
			return R.fail("代付金额不能超过商户每日限额(限额 : 发起金额(不含手续费) = " + bussiness.getMaxLimit().toString() + ":" + totalAmount.toString() + ")");
		}else{
			//获取今日采购商已分润金额
			BusinessDeptDaliyStat todayStat = businessDeptDailyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDailyStatService.createTodayStat(bussiness.getId(), null);
			}else{
				//今日已分润金额
				BigDecimal todayAmount = todayStat.getStatAmount();
				if(todayAmount.add(totalAmount).compareTo(bussiness.getMaxLimit()) == 1){ //如果当日已分润金额+本次订单分润金额大于商户每日上限分润金额
					log.error("=================代付请求前校验，今日提现金额已超过商户每日限额=================");
					return R.fail("今日代付金额已超过商户每日限额");
				}
			}
		}
		//1、先发起一次子商户转账到平台商户
		//2、如果余额小于订单金额+提现手续费+转账手续费*2，则认为不可以发起代付
		R<BigDecimal> bussinessRemainR = bussinessService.queryBalance(bussiness.getMerchantNo());
		String withdrawRate = paramService.getValue("yee_withdraw_rate");
		String transferRate = paramService.getValue("yee_transfer_rate");
		BigDecimal remain = bussinessRemainR.getData();
		DecimalFormat payDecimalFormat = new DecimalFormat("0.00");
		BigDecimal totalOrderAmount = new BigDecimal(payDecimalFormat.format(totalAmount));
		BigDecimal withdrawFee = new BigDecimal(withdrawRate);
		BigDecimal transferFee = new BigDecimal(transferRate);
		BigDecimal transferAmount = totalOrderAmount.add(transferFee.multiply(BigDecimal.valueOf(withdrawRequestExcelList.size()))).add(withdrawFee.multiply(BigDecimal.valueOf(withdrawRequestExcelList.size()))); //这里包含实际提现金额，提现手续费以及帮平台商承担的转账手续费
		if(remain.compareTo(transferAmount.add(transferFee.multiply(BigDecimal.valueOf(withdrawRequestExcelList.size())))) == -1){
			return R.fail("商户余额不足，无法发起代付。");
		}
		this.bussinessPayService.importPayToUserList(withdrawRequestExcelList, bussiness);
		return R.success("导入成功");
	}

	/**
	 *  重新发起付款（补发）
	 * */
	@PostMapping("/rePayToUser")
	public R rePayToUser(@RequestParam Long withdrawId){
		String maintain = paramService.getValue("maintain");
		if(StringUtil.isNotBlank(maintain)){
			if(maintain.equals("0")){ //进入维护时间
				return R.fail("系统维护时间为每天晚上22:00-凌晨07:00");
			}
		}
		R result = this.bussinessPayService.rePayToUser(withdrawId);
		return result;
	}

	@PostMapping("/user/submit")
	public R userSubmit(@RequestBody UserSubmitDto userSubmitDto){
		return this.bussinessPayService.userSubmit(userSubmitDto);
	}

	@PostMapping("/user/register")
	public R userRegister(@Valid @RequestBody UserRegisterDto userRegisterDto){
		if(StringUtil.isBlank(userRegisterDto.getUserId())){
			//发起一个新用户的进件
			return this.bussinessPayService.userRegister(userRegisterDto);
		}else{
			//针对一个旧用户再次发起进件
			return this.bussinessPayService.userRegisterUpdate(userRegisterDto);
		}
	}

	/**
	 * 构建小微用户信息
	 * @param payToUserDto
	 * @param bussinessId 所属关联商户
	 * @return
	 */
	private BussinessUserInfo toUserInfo(PayToUserDto payToUserDto, Long bussinessId){
		BussinessUserInfo userInfo = new BussinessUserInfo();
		userInfo.setUserName(payToUserDto.getUserName());
		userInfo.setUserShortName(payToUserDto.getUserName());
		userInfo.setUserLicenceNo(payToUserDto.getUserLicenceNo());
		userInfo.setUserLicenceType("ID_CARD");
		userInfo.setUserCardFrontUrl(payToUserDto.getUserCardFrontUrl());
		userInfo.setUserCardBackUrl(payToUserDto.getUserCardBackUrl());
		userInfo.setThirdUserCardBackUrl(payToUserDto.getUserCardBackUrl());
		userInfo.setBankCode(payToUserDto.getReceiverBankCode());
		userInfo.setBankCardNo(payToUserDto.getReceiverAccountNo());
		userInfo.setBankAccountType(StringUtil.isNotBlank(payToUserDto.getBankAccountType()) ? payToUserDto.getBankAccountType() : "DEBIT_CARD");
		userInfo.setUserPhone(payToUserDto.getUserPhone());
		userInfo.setBussinessId(bussinessId);
		return userInfo;
	}


	/**
	 * 创建小微用户进件申请和提现账单
	 * @param userInfo
	 * @param payToUserDto
	 * @return
	 */
	private R userRegisterAndCreateWithdraw(BussinessUserInfo userInfo, PayToUserDto payToUserDto, String requestIp){
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		//先保存一个进件请求对象
		BussinessRegisterRequest bussinessRegisterRequest = new BussinessRegisterRequest();
		bussinessRegisterRequest.setUserInfoId(userInfo.getId());
		boolean requestSave = this.bussinessRegisterRequestService.save(bussinessRegisterRequest);
		if(requestSave){
			R result = this.createWithDrawOrder(userInfo, null, payToUserDto.getBussinessOrderId(), bussinessRegisterRequest.getId(), new BigDecimal(debitDecimalFormat.format(payToUserDto.getOrderAmount())), null, null, requestIp);
			if(result.isSuccess()){
				R registerResult = bussinessRegisterRequestService.userRegister(bussinessRegisterRequest.getId(), userInfo.getId());
				if(registerResult.isSuccess()){
					return R.data("PROCESSING", "代付受理成功，请等待结果");
				}else{
					return R.data(400, "FAIL", registerResult.getMsg());
				}
			}else{
				return R.data(400, "FAIL","代付失败(CODE:40001)");
			}
		}else{
			return R.data(400, "FAIL", "代付失败(CODE:40002)");
		}
	}

	/**
	 * 创建小微用户进件申请和提现账单
	 * @param userInfo
	 * @param excel
	 * @return
	 */
	private R userRegisterAndCreateWithdraw(BussinessUserInfo userInfo, WithdrawRequestExcel excel, String requestIp){
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		//先保存一个进件请求对象
		BussinessRegisterRequest bussinessRegisterRequest = new BussinessRegisterRequest();
		bussinessRegisterRequest.setUserInfoId(userInfo.getId());
		boolean requestSave = this.bussinessRegisterRequestService.save(bussinessRegisterRequest);
		if(requestSave){
			R result = this.createWithDrawOrder(userInfo, null,null, bussinessRegisterRequest.getId(), new BigDecimal(debitDecimalFormat.format(excel.getOrderAmount())), null, null, requestIp);
			if(result.isSuccess()){
				R registerResult = this.bussinessRegisterRequestService.userRegister(bussinessRegisterRequest.getId(), userInfo.getId());
				if(registerResult.isSuccess()){
					return R.success("代付受理成功，请等待结果");
				}else{
					return R.fail("代付失败(CODE:40000)");
				}
			}else{
				return R.fail("代付失败(CODE:40001)");
			}
		}else{
			return R.fail("代付失败(CODE:40002)");
		}
	}

	private R<BussinessUserWithdraw> createWithDrawOrder(BussinessUserInfo userInfo, Long transferOrderId, String bussinessOrderId, Long userRegisterRequestId, BigDecimal withdrawAmount, String failReason, String returnMsg, String requestIp){
		BussinessUserWithdraw withdraw = new BussinessUserWithdraw();
		withdraw.setUserInfoId(userInfo.getId());
		withdraw.setMerchantNo(userInfo.getMerchantNo());
		withdraw.setBankAccountNo(userInfo.getBankCardNo());
		withdraw.setFirstTransferOrderId(transferOrderId);
		withdraw.setOrderAmount(withdrawAmount);
		withdraw.setReceiveType("REAL_TIME");
		withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.WAIT.getValue());
		withdraw.setFailReason(failReason);
		withdraw.setReturnMsg(returnMsg);
		withdraw.setBussinessOrderId(bussinessOrderId);
		withdraw.setUserRegisterRequestId(userRegisterRequestId);
		withdraw.setRequestNo(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
		withdraw.setRequestIp(requestIp);
		withdraw.setReceiverAccountName(userInfo.getUserName());
		withdraw.setBankCode(userInfo.getBankCode());
		withdraw.setBussinessId(userInfo.getBussinessId());
		boolean save = this.withdrawService.save(withdraw);
		if(save){
			return R.data(withdraw);
		}else{
			return R.fail("提现订单保存失败");
		}
	}

	/**
	 * 提现前发起第一次转账到平台商
	 * @param userInfo
	 * @param merchantNo
	 * @param payToUserDto
	 * @return
	 */
	private R<Long> transferOrderToPlatform(BussinessUserInfo userInfo, String merchantNo, String transferAmount, PayToUserDto payToUserDto, String requestIp){
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		BigDecimal orderAmountBigDecimal = new BigDecimal(debitDecimalFormat.format(payToUserDto.getOrderAmount()));
		BussinessTransferOrder firstTransferOrder = new BussinessTransferOrder();
		firstTransferOrder.setFromMerchantNo(merchantNo);
		firstTransferOrder.setToMerchantNo(userInfo.getParentMerchantNo());
		firstTransferOrder.setTransferUsage("采购");
		firstTransferOrder.setOrderAmount(transferAmount);
		firstTransferOrder.setFeeChargeSide("OUTSIDE");
		firstTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
		firstTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_FIRST_TRANSFER.getValue());
		firstTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
		bussinessTransferOrderService.save(firstTransferOrder);
		R<BussinessUserWithdraw> withDrawOrderResult = this.createWithDrawOrder(userInfo, firstTransferOrder.getId(), payToUserDto.getBussinessOrderId(), null, orderAmountBigDecimal, "受理成功，请等待结果", "提现前第一次转账发起受理成功", requestIp);
		if(withDrawOrderResult.isSuccess()){
			R firstTransferResult = this.bussinessPayService.transferOrder(firstTransferOrder, userInfo.getParentMerchantNo());
			BussinessUserWithdraw dbWithdraw = withDrawOrderResult.getData();
			if(firstTransferResult.isSuccess()){
				dbWithdraw.setFailReason("受理成功，请等待结果");
				dbWithdraw.setReturnMsg(firstTransferResult.getMsg());
				this.withdrawService.updateById(dbWithdraw);
				if(firstTransferResult.getMsg().equals("REQUEST_RECEIVE")){
					this.handleFirstTransferScene(firstTransferOrder.getId());
				}else if(firstTransferResult.getMsg().equals("SUCCESS")){
					String withdrawRate = paramService.getValue("yee_withdraw_rate");
					BussinessTransferOrder secondTransferOrder = new BussinessTransferOrder();
					secondTransferOrder.setFromMerchantNo(firstTransferOrder.getToMerchantNo());
					secondTransferOrder.setToMerchantNo(dbWithdraw.getMerchantNo());
					secondTransferOrder.setTransferUsage("提现前转账");
					secondTransferOrder.setOrderAmount((dbWithdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
					secondTransferOrder.setFeeChargeSide("OUTSIDE");
					secondTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
					secondTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
					secondTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
					this.transferOrderService.save(secondTransferOrder);
					dbWithdraw.setSecondTransferOrderId(secondTransferOrder.getId());
					this.withdrawService.updateById(dbWithdraw);
					R secondTransferResult = this.transferOrderService.transferOrder(secondTransferOrder, firstTransferOrder.getToMerchantNo());
					if(secondTransferResult.isSuccess()){
						if(secondTransferResult.getMsg().equals("REQUEST_RECEIVE")){
							this.handleSecondTransferScene(secondTransferOrder.getId());
						}else if(secondTransferResult.getMsg().equals("SUCCESS")){
							this.bussinessPayService.withdrawOrder(dbWithdraw, userInfo.getParentMerchantNo());
						}
					}else{
						dbWithdraw.setFailReason("代付失败");
						dbWithdraw.setReturnMsg(secondTransferResult.getMsg());
						dbWithdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
						this.withdrawService.updateById(dbWithdraw);
						return R.fail("代付失败");
					}
				}
				return R.success("受理成功，请等待结果");
			}else{
				dbWithdraw.setFailReason("代付失败");
				dbWithdraw.setReturnMsg(firstTransferResult.getMsg());
				dbWithdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.FAIL.getValue());
				this.withdrawService.updateById(dbWithdraw);
				return R.data(400, firstTransferOrder.getId(), firstTransferResult.getMsg());
			}
		}else{
			return R.fail("代付失败(CODE:YWSB)");
		}
	}

	/**
	 * 提现前发起第一次转账到平台商
	 * @param userInfo
	 * @param merchantNo
	 * @param excel
	 * @return
	 */
	private R<Long> transferOrderToPlatform(BussinessUserInfo userInfo, String merchantNo, String transferAmount, WithdrawRequestExcel excel){
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		BigDecimal orderAmountBigDecimal = new BigDecimal(debitDecimalFormat.format(excel.getOrderAmount()));
		BussinessTransferOrder firstTransferOrder = new BussinessTransferOrder();
		firstTransferOrder.setFromMerchantNo(merchantNo);
		firstTransferOrder.setToMerchantNo(userInfo.getParentMerchantNo());
		firstTransferOrder.setTransferUsage("采购");
		firstTransferOrder.setOrderAmount(transferAmount);
		firstTransferOrder.setFeeChargeSide("OUTSIDE");
		firstTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
		firstTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_FIRST_TRANSFER.getValue());
		firstTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
		this.transferOrderService.save(firstTransferOrder);
		R<BussinessUserWithdraw> withDrawOrderResult = this.createWithDrawOrder(userInfo, firstTransferOrder.getId(),null, null, orderAmountBigDecimal, "受理成功，请等待结果", "提现前第一次转账发起受理成功", null);
		if(withDrawOrderResult.isSuccess()){
			R firstTransferResult = transferOrderService.transferOrder(firstTransferOrder, userInfo.getParentMerchantNo());
			if(firstTransferResult.isSuccess()){
				BussinessUserWithdraw dbWithdraw = withDrawOrderResult.getData();
				dbWithdraw.setFailReason("受理成功，请等待结果");
				dbWithdraw.setReturnMsg(firstTransferResult.getMsg());
				this.withdrawService.updateById(dbWithdraw);
				if(firstTransferResult.getMsg().equals("REQUEST_RECEIVE")){
					this.handleFirstTransferScene(firstTransferOrder.getId());
				}else if(firstTransferResult.getMsg().equals("SUCCESS")){
					String withdrawRate = paramService.getValue("yee_withdraw_rate");
					BussinessTransferOrder secondTransferOrder = new BussinessTransferOrder();
					secondTransferOrder.setFromMerchantNo(firstTransferOrder.getToMerchantNo());
					secondTransferOrder.setToMerchantNo(dbWithdraw.getMerchantNo());
					secondTransferOrder.setTransferUsage("提现前转账");
					secondTransferOrder.setOrderAmount((dbWithdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
					secondTransferOrder.setFeeChargeSide("OUTSIDE");
					secondTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
					secondTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
					secondTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
					this.transferOrderService.save(secondTransferOrder);
					dbWithdraw.setSecondTransferOrderId(secondTransferOrder.getId());
					this.withdrawService.updateById(dbWithdraw);
					R secondTransferResult = this.transferOrderService.transferOrder(secondTransferOrder, firstTransferOrder.getToMerchantNo());
					if(secondTransferResult.isSuccess()){
						if(secondTransferResult.getMsg().equals("REQUEST_RECEIVE")){
							this.handleSecondTransferScene(secondTransferOrder.getId());
						}else if(secondTransferResult.getMsg().equals("SUCCESS")){
							this.bussinessPayService.withdrawOrder(dbWithdraw, userInfo.getParentMerchantNo());
						}
					}else{
						dbWithdraw.setFailReason("代付失败");
						dbWithdraw.setReturnMsg(secondTransferResult.getMsg());
						this.withdrawService.updateById(dbWithdraw);
						return R.fail("代付失败");
					}
				}
				return R.success("受理成功，请等待结果");
			}else{
				return R.data(400, firstTransferOrder.getId(), firstTransferResult.getMsg());
			}
		}else{
			return R.fail("代付失败(CODE:YWSB)");
		}
	}

	public void handleFirstTransferScene(Long firstTransferOrderId){
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				BussinessTransferOrder firstTransferOrder = transferOrderService.getById(firstTransferOrderId);
				if(firstTransferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.REQUEST_RECEIVE.getValue()){
					try{
						R result = transferOrderService.transferQuery(firstTransferOrder.getId());
						if(result.isSuccess()){
							if(result.getData().equals("SUCCESS")){
								String withdrawRate = paramService.getValue("yee_withdraw_rate");
								BussinessUserWithdraw withdraw = withdrawService.getByFirstTransferOrderId(firstTransferOrderId);
								BussinessTransferOrder secondTransferOrder = new BussinessTransferOrder();
								secondTransferOrder.setFromMerchantNo(firstTransferOrder.getToMerchantNo());
								secondTransferOrder.setToMerchantNo(withdraw.getMerchantNo());
								secondTransferOrder.setTransferUsage("提现前转账");
								secondTransferOrder.setOrderAmount((withdraw.getOrderAmount().add(new BigDecimal(withdrawRate))).toString());
								secondTransferOrder.setFeeChargeSide("OUTSIDE");
								secondTransferOrder.setRequestNo(UUID.randomUUID().toString().replaceAll("-","").toUpperCase());
								secondTransferOrder.setTransferScene(SystemConstant.TransferScene.FOR_WITHDRAW_SECOND_TRANSFER.getValue());
								secondTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
								transferOrderService.save(secondTransferOrder);
								withdraw.setSecondTransferOrderId(secondTransferOrder.getId());
								withdrawService.updateById(withdraw);
								R secondTransferResult = transferOrderService.transferOrder(secondTransferOrder, firstTransferOrder.getToMerchantNo());
								if(secondTransferResult.isSuccess()){
									if(secondTransferResult.getMsg().equals("REQUEST_RECEIVE")){
										handleSecondTransferScene(secondTransferOrder.getId());
									}else if(secondTransferResult.getMsg().equals("SUCCESS")){
										bussinessPayService.withdrawOrder(withdraw, secondTransferOrder.getFromMerchantNo());
									}
								}else{
									withdraw.setFailReason("代付失败");
									withdraw.setReturnMsg(secondTransferResult.getMsg());
									withdrawService.updateById(withdraw);
								}
								this.cancel();
								timer.cancel();
							}
						}else{
							this.cancel();
							timer.cancel();
						}
					}catch (Exception e){
						this.cancel();
						timer.cancel();
					}
				}else{
					this.cancel();
					timer.cancel();
				}
			}
		}, 500 , 10000);
	}

	public void handleSecondTransferScene(Long secondTransferOrderId){
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				BussinessTransferOrder firstTransferOrder = transferOrderService.getById(secondTransferOrderId);
				if(firstTransferOrder.getTransferStatus().intValue() == SystemConstant.TransferOrderStatus.REQUEST_RECEIVE.getValue()){
					try{
						R result = transferOrderService.transferQuery(secondTransferOrderId);
						if(result.isSuccess()){
							if(result.getData().equals("SUCCESS")){
								BussinessUserWithdraw withdraw = withdrawService.getBySecondTransferOrderId(secondTransferOrderId);
								Long userInfoId = withdraw.getUserInfoId();
								BussinessUserInfo userInfo = userInfoService.getById(userInfoId);
								withdraw.setReturnMsg("提现前第二次转账成功");
								bussinessPayService.withdrawOrder(withdraw, userInfo.getParentMerchantNo());
								this.cancel();
								timer.cancel();
							}
						}else{
							this.cancel();
							timer.cancel();
						}
					}catch (Exception e){
						this.cancel();
						timer.cancel();
					}
				}else{
					this.cancel();
					timer.cancel();
				}
			}
		}, 500 , 10000);
	}

	private BussinessDebit generateDebit(PayOrderDto payOrderDto){
		BussinessDebit bussinessDebit = new BussinessDebit();
		bussinessDebit.setFee(BigDecimal.valueOf(1));
		bussinessDebit.setPrice(BigDecimal.valueOf(payOrderDto.getOrderAmount()));
		bussinessDebit.setType(SystemConstant.BussinessDebitType.COMMISSION.getValue());
		bussinessDebit.setBankAccountType(payOrderDto.getBankAccountType());
		bussinessDebit.setReceiverAccountName(payOrderDto.getReceiverAccountName());
		bussinessDebit.setReceiverAccountNo(payOrderDto.getReceiverAccountNo());
		bussinessDebit.setReceiverBankCode(payOrderDto.getReceiverBankCode());
		bussinessDebit.setBussinessOrderId(payOrderDto.getBussinessOrderId());
		bussinessDebit.setMethod(2);//表示api对接
		bussinessDebit.setFreeze(String.valueOf(payOrderDto.getOrderAmount()));
		return bussinessDebit;
	}

	public static void main(String[] args){
		String remain = "FF4B299BBD4357507945013F418D21A9";
		String decrypt = MoneyDesUtil.decrypt(remain, MoneyDesUtil.KEY_FOR_UC);
		System.out.printf(decrypt);
	}
}
