/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.guosen.bussiness.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.SystemConstant;
import org.springblade.common.utils.MoneyDesUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
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.DebitRequestExcel;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitService;
import org.springblade.modules.guosen.bussiness.service.IBussinessService;
import org.springblade.modules.guosen.bussiness.vo.BussinessDebitRequestVO;
import org.springblade.modules.guosen.bussiness.mapper.BussinessDebitRequestMapper;
import org.springblade.modules.guosen.bussiness.service.IBussinessDebitRequestService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.guosen.bussinessInfo.entity.BussinessInfo;
import org.springblade.modules.guosen.bussinessInfo.service.IBussinessInfoService;
import org.springblade.modules.guosen.bussinessTransferOrder.entity.BussinessTransferOrder;
import org.springblade.modules.guosen.bussinessTransferOrder.service.IBussinessTransferOrderService;
import org.springblade.modules.guosen.debtDaliyStat.entity.BusinessDeptDaliyStat;
import org.springblade.modules.guosen.debtDaliyStat.service.IBusinessDeptDaliyStatService;
import org.springblade.modules.obs.service.ObsService;
import org.springblade.modules.system.service.IParamService;
import org.springblade.yeePay.common.YeePayConst;
import org.springblade.yeePay.entity.BatchTransferDto;
import org.springblade.yeePay.entity.PayOrderDto;
import org.springblade.yeePay.service.BussinessPayService;
import org.springblade.yeePay.service.YeePayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 *  服务实现类
 *
 * @author BladeX
 * @since 2021-07-20
 */
@Slf4j
@Service
public class BussinessDebitRequestServiceImpl extends BaseServiceImpl<BussinessDebitRequestMapper, BussinessDebitRequest> implements IBussinessDebitRequestService {


	@Autowired
	private IBussinessService bussinessService;
	@Autowired
	private ObsService obsService;
	@Autowired
	private IBussinessDebitService bussinessDebitService;
	@Autowired
	private YeePayService yeePayService;
	@Value("${pay.noticeUrl}")
	private String payNoticeUrl;
	@Autowired
	IBusinessDeptDaliyStatService businessDeptDaliyStatService;
	@Autowired
	private IParamService paramService;
	@Autowired
	private YeePayConst yeePayConst;
	@Autowired
	private IBussinessTransferOrderService bussinessTransferOrderService;
	@Autowired
	private BussinessPayService bussinessPayService;
	@Autowired
	private IBussinessInfoService bussinessInfoService;

	@Override
	public IPage<BussinessDebitRequestVO> selectBussinessDebitRequestPage(IPage<BussinessDebitRequestVO> page, BussinessDebitRequestVO bussinessDebitRequest) {
		return page.setRecords(baseMapper.selectBussinessDebitRequestPage(page, bussinessDebitRequest));
	}

	@Override
	@Transactional
	public R importList(MultipartFile file, BladeUser bladeUser) {
		//上传附件
		String fileUrl = null;
		try {
			fileUrl = obsService.postObject(file);
		} catch (IOException e) {
			e.printStackTrace();
			Assert.isFalse(true,"上传文件失败");
		}
		//将表格解析为list
		List<DebitRequestExcel> debitRequestExcels = ExcelUtil.read(file,DebitRequestExcel.class);
		Assert.isFalse(debitRequestExcels.size() == 0,"表格中无记录");
		//获取当前采购商的可用余额
		Bussiness bussiness = bussinessService.getBaseMapper().selectOne(new QueryWrapper<>(new Bussiness()).lambda()
			.eq(Bussiness::getAccountId, bladeUser.getUserId()));
		Assert.notNull(bussiness,"当前登录用户不是采购商，无法执行此操作");
		if(bussiness.getRegisterStatus() == null || bussiness.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			log.error("=================代付请求前校验，商户未完成进件审核=================");
			return R.fail("请先完成商户进件审核");
		}
		//本次代付订单金额
		BigDecimal totalAmount = debitRequestExcels.stream().map(
				debitRequestExcel -> BigDecimal.valueOf(debitRequestExcel.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 = businessDeptDaliyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDaliyStatService.createTodayStat(bussiness.getId(), null);
			}else{
				//今日已分润金额
				BigDecimal todayAmount = todayStat.getStatAmount();
				if(todayAmount.add(totalAmount).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();
		BigDecimal payFee = new BigDecimal(1.00);
		BigDecimal transferFee = new BigDecimal(1.00);
		DecimalFormat debitDecimalFormat = new DecimalFormat("0.00");
		BigDecimal totalOrderAmount = new BigDecimal(debitDecimalFormat.format(totalAmount));
		BigDecimal transferAmount = totalOrderAmount.add(payFee.multiply(BigDecimal.valueOf(debitRequestExcels.size()))).add(transferFee.multiply(BigDecimal.valueOf(debitRequestExcels.size())));
		//如果余额小于订单金额+代付手续费+转账手续费，则认为不可以发起代付
		if(remain.compareTo(transferAmount) == -1){
			return R.fail("商户余额不足，无法发起代付。");
		}

		//保存采购商批量分佣请求对象
		BussinessDebitRequest bussinessDebitRequest = new BussinessDebitRequest();
		bussinessDebitRequest.setBussinessId(bussiness.getId());
		bussinessDebitRequest.setAttachUrl(fileUrl);
		bussinessDebitRequest.setOrderCount(debitRequestExcels.size());//订单总笔数
		bussinessDebitRequest.setStatus(0);//0为易宝未回调状态
		bussinessDebitRequest.setAttachName(file.getOriginalFilename());
		if(this.save(bussinessDebitRequest)){
			//保存采购商批量分佣明细
			for(DebitRequestExcel debitRequestExcel : debitRequestExcels){
				try{
					BussinessDebit bussinessDebit = new BussinessDebit();
					bussinessDebit.setFee(new BigDecimal(1.00));
					bussinessDebit.setPrice(new BigDecimal(debitDecimalFormat.format(debitRequestExcel.getOrderAmount())));
					bussinessDebit.setType(SystemConstant.BussinessDebitType.COMMISSION.getValue());
					bussinessDebit.setBankAccountType(debitRequestExcel.getBankAccountType());
					bussinessDebit.setReceiverAccountName(debitRequestExcel.getReceiverAccountName());
					bussinessDebit.setReceiverAccountNo(debitRequestExcel.getReceiverAccountNo());
					bussinessDebit.setReceiverBankCode(debitRequestExcel.getReceiverBankCode());
					bussinessDebit.setBussinessId(bussiness.getId());
					bussinessDebit.setMethod(1); //xml导入方式
					bussinessDebit.setRequestId(bussinessDebitRequest.getId());
					String debitFormat = debitDecimalFormat.format(bussinessDebit.getPrice());
					bussinessDebit.setFreeze(debitFormat);
					bussinessDebit.setCurrentRemain(remain.toString());
					if(bussinessDebitService.save(bussinessDebit)){

					}else{
						Assert.isFalse(true,"明细保存失败，请检查表格数据格式的正确性");
					}
				}catch (Exception e){
					e.printStackTrace();
					Assert.isFalse(true,"明细保存失败，请检查表格数据格式的正确性");
				}
			}
			//通过requestId获取明细列表
			List<BussinessDebit> bussinessDebits = bussinessDebitService.getBaseMapper().selectList(
				new QueryWrapper<>(new BussinessDebit()).lambda().eq(BussinessDebit::getRequestId,bussinessDebitRequest.getId())
			);

			//从批量中拆分一笔笔代付
			singlePayByBatch(bussinessDebits, bussiness, bussinessInfo.getParentMerchantNo());

			return R.status(true);
		}else{
			Assert.isFalse(true,"账单请求保存失败");
		}

		return R.status(false);
	}

	//从批量中拆分一笔笔代付
	/*{
		"orderAmount":0.50,
		"receiveType":"REAL_TIME",
		"receiverAccountNo":"6222033602001383333",
		"receiverAccountName":"张祥",
		"receiverBankCode":"ICBC",
		"bankAccountType": "DEBIT_CARD",
		"bussinessOrderId":"0494843884543"
	}*/
	private void singlePayByBatch(List<BussinessDebit> bussinessDebits, Bussiness bussiness, String parentMerchantNo){
		if(bussinessDebits != null && bussinessDebits.size() > 0) {
			for (BussinessDebit debit : bussinessDebits) {
				BussinessTransferOrder bussinessTransferOrder = new BussinessTransferOrder();
				bussinessTransferOrder.setFromMerchantNo(bussiness.getMerchantNo());
				bussinessTransferOrder.setToMerchantNo(parentMerchantNo);
				bussinessTransferOrder.setTransferUsage("采购");
				bussinessTransferOrder.setOrderAmount(debit.getPrice().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, parentMerchantNo);
					if(transferResult.isSuccess()){
						debit.setTransferOrderId(bussinessTransferOrder.getId());
						bussinessDebitService.updateById(debit);
					}else{
						debit.setTransferOrderId(bussinessTransferOrder.getId());
						debit.setStatus(SystemConstant.BussinessDebitStatus.FAIL.getValue());
						debit.setFreeze("0.00");
						debit.setFailReason("代付失败");
						bussinessDebitService.updateById(debit);
					}
				}else{
					log.error("====================代付前转账业务订单保存失败====================");
					log.error(JSONUtil.toJsonStr(bussinessTransferOrder));
					debit.setStatus(SystemConstant.BussinessDebitStatus.ERROR.getValue());
					bussinessDebitService.updateById(debit);
				}
			}
		}
	}

	@Override
	public R payOrder(PayOrderDto payOrderDto, String requestIp) {
		String maintain = paramService.getValue("maintain");
		if(StringUtil.isNotBlank(maintain)){
			if(maintain.equals("0")){ //进入维护时间
				return R.fail("系统维护时间为每天晚上22:00-凌晨07:00");
			}
		}
		Bussiness bussiness = this.bussinessService.getById(payOrderDto.getBussinessId());
		if(bussiness == null){
			log.error("=================代付请求前校验，平台采购商不存在=================");
			return R.fail("商户不存在");
		}
		if(bussiness.getRegisterStatus() == null || bussiness.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			log.error("=================代付请求前校验，商户未完成进件审核=================");
			return R.fail("请先完成商户进件审核");
		}
		//检查采购商余额
		R<BigDecimal> remainR = bussinessService.queryBalance(bussiness.getMerchantNo());
		BigDecimal remain = remainR.getData();
		if(remain.compareTo(new BigDecimal(payOrderDto.getOrderAmount()).add(new BigDecimal(1))) == -1){
			return R.fail("商户余额不足，请重新下单采购");
		}
		if(BigDecimal.valueOf(payOrderDto.getOrderAmount()).compareTo(bussiness.getMaxLimit()) == 1){ //大于的时候返回1，等于返回0，小于返回-1
			log.error("=================代付请求前校验，提现金额不能超过商户每日限额=================");
			return R.fail("提现金额不能超过商户每日限额" + payOrderDto.getOrderAmount());
		}else{
			//获取今日采购商已分润金额
			BusinessDeptDaliyStat todayStat = businessDeptDaliyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDaliyStatService.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());
		//保存采购商单笔分佣请求对象
		BussinessDebitRequest bussinessDebitRequest = new BussinessDebitRequest();
		bussinessDebitRequest.setBussinessId(bussiness.getId());
		bussinessDebitRequest.setOrderCount(1);//订单总笔数
		bussinessDebitRequest.setStatus(0);//0为易宝未回调状态
		if(this.save(bussinessDebitRequest)){
			BussinessDebit debit = null;
			debit = this.generateDebit(payOrderDto);
			debit.setRequestId(bussinessDebitRequest.getId());
			debit.setBussinessId(bussiness.getId());
			debit.setRequestIp(requestIp);
			debit.setCurrentRemain(MoneyDesUtil.decrypt(bussiness.getRemain(), MoneyDesUtil.KEY_FOR_UC));
			String requestNo = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
			debit.setRequestNo(requestNo);
			payOrderDto.setRequestNo(requestNo);
			if(this.bussinessDebitService.save(debit)){
				R result = this.yeePayService.payOrder(payOrderDto, bussinessInfo.getParentMerchantNo());
				if(result.isSuccess()){
					JSONObject data = JSONUtil.parseObj(result.getData());
					String returnCode = data.getStr("returnCode");
					String returnMsg = data.getStr("returnMsg");
					String orderNo = data.getStr("orderNo");
					String msg = returnMsg;
					debit.setThirdPayLog(JSONUtil.toJsonStr(data));
					if(StringUtil.isNotBlank(returnCode) && returnCode.equals("UA00000")) { //代付发起成功
						log.info("========================单笔代付发起成功====================");
						debit.setThirdOrderNo(orderNo);
						bussinessDebitService.updateById(debit);
						return R.data(data, msg);
					} else{
						log.error("========================单笔代付发起失败====================");
						log.error(msg);
						debit.setStatus(SystemConstant.BussinessDebitStatus.FAIL.getValue());
						debit.setFreeze("0.00");
						debit.setFailReason(msg);
						bussinessDebitService.updateById(debit);
						return R.data(400, data, msg);
					}
				}else{
					log.error("========================单笔代付发起失败====================");
					log.error(result.getMsg());
					debit.setFreeze("0.00");
					bussinessDebitService.updateById(debit);
					return R.fail(result.getMsg());
				}
			}else{
				log.error("=================代付请求前校验，明细保存失败=================");
				return R.fail("明细保存失败");
			}
		}else{
			log.error("=================代付请求前校验，请求实例保存失败=================");
			return R.fail("请求实例保存失败");
		}
	}

	public 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;
	}

	private BatchTransferDto getBatchPayObject(List<BussinessDebit> bussinessDebits){

		//批次号
		String batchNo = bussinessDebits.get(0).getRequestId().toString();
		//到账类型
		String receiveType = "REAL_TIME";
		//订单详情
		List<BatchTransferDto.DetailList> detailList = new ArrayList<>();
		bussinessDebits.forEach(bussinessDebit -> {
			BatchTransferDto.DetailList detail= new BatchTransferDto.DetailList();

			detail.setBankAccountType(bussinessDebit.getBankAccountType());
			detail.setFeeChargeSide("PAYER");
			detail.setOrderAmount(Double.valueOf(bussinessDebit.getPrice().toString()));
			detail.setReceiverAccountName(bussinessDebit.getReceiverAccountName());
			detail.setReceiverBankCode(bussinessDebit.getReceiverBankCode());
			detail.setReceiverAccountNo(bussinessDebit.getReceiverAccountNo());
			detail.setRequestNo(bussinessDebit.getId().toString());
			detailList.add(detail);
		});
		return BatchTransferDto.builder().batchNo(batchNo).receiveType(receiveType).detailList(detailList).build();
	}

}
