/*
 *      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.bussinessuserwithdraw.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springblade.common.constant.SystemConstant;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.modules.guosen.bankcode.entity.BankCode;
import org.springblade.modules.guosen.bankcode.service.IBankCodeService;
import org.springblade.modules.guosen.bussiness.entity.Bussiness;
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.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.dto.WithdrawTransferOrder;
import org.springblade.modules.guosen.bussinessuserwithdraw.entity.BussinessUserWithdraw;
import org.springblade.modules.guosen.bussinessuserwithdraw.excel.WithdrawExcel;
import org.springblade.modules.guosen.bussinessuserwithdraw.vo.BussinessUserWithdrawVO;
import org.springblade.modules.guosen.bussinessuserwithdraw.mapper.BussinessUserWithdrawMapper;
import org.springblade.modules.guosen.bussinessuserwithdraw.service.IBussinessUserWithdrawService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.guosen.debtDaliyStat.entity.BusinessDeptDaliyStat;
import org.springblade.modules.guosen.debtDaliyStat.service.IBusinessDeptDaliyStatService;
import org.springblade.modules.system.service.IParamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  服务实现类
 *
 * @author BladeX
 * @since 2021-10-11
 */
@Service
public class BussinessUserWithdrawServiceImpl extends BaseServiceImpl<BussinessUserWithdrawMapper, BussinessUserWithdraw> implements IBussinessUserWithdrawService {

	@Autowired
	private IBussinessUserInfoService userInfoService;
	@Autowired
	private IBussinessService bussinessService;
	@Autowired
	private IParamService paramService;
	@Autowired
	IBusinessDeptDaliyStatService businessDeptDaliyStatService;
	@Autowired
	private IBussinessInfoService bussinessInfoService;
	@Autowired
	private IBussinessTransferOrderService transferOrderService;
	@Autowired
	private IBankCodeService bankCodeService;

	@Override
	public IPage<BussinessUserWithdrawVO> selectBussinessUserWithdrawPage(IPage<BussinessUserWithdrawVO> page, BussinessUserWithdrawVO bussinessUserWithdraw) {
		return page.setRecords(baseMapper.selectBussinessUserWithdrawPage(page, bussinessUserWithdraw));
	}

	@Override
	public BussinessUserWithdraw getByFirstTransferOrderId(Long firstTransferOrderId) {
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = new LambdaQueryWrapper<>();
		lambda.eq(BussinessUserWithdraw::getFirstTransferOrderId, firstTransferOrderId);
		return baseMapper.selectOne(lambda);
	}

	@Override
	public BussinessUserWithdraw getBySecondTransferOrderId(Long secondTransferOrderId) {
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = new LambdaQueryWrapper<>();
		lambda.eq(BussinessUserWithdraw::getSecondTransferOrderId, secondTransferOrderId);
		return baseMapper.selectOne(lambda);
	}

	@Override
	public BussinessUserWithdraw getByUserRegisterRequestId(Long userRegisterRequestId) {
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = new LambdaQueryWrapper<>();
		lambda.eq(BussinessUserWithdraw::getUserRegisterRequestId, userRegisterRequestId);
		return baseMapper.selectOne(lambda);
	}

	@Override
	public BussinessUserWithdraw getByRequestNo(String requestNo) {
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = new LambdaQueryWrapper<>();
		lambda.eq(BussinessUserWithdraw::getRequestNo, requestNo);
		return baseMapper.selectOne(lambda);
	}

	@Override
	public List<BussinessUserWithdraw> getByBussinessOrderId(Long bussinessId, List<String> bussinessOrderId) {
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = new LambdaQueryWrapper<>();
		lambda.eq(BussinessUserWithdraw::getBussinessId, bussinessId);
		lambda.in(BussinessUserWithdraw::getBussinessOrderId, bussinessOrderId);
		lambda.orderByDesc(BussinessUserWithdraw::getCreateTime);
		List<BussinessUserWithdraw> list = this.list(lambda);
		return list;
	}

	@Override
	public BigDecimal withdrawStat(BussinessUserWithdraw withdraw) {
		Date createTime = withdraw.getCreateTime();
		String createTimeFormat = null;
		if(createTime != null){
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			createTimeFormat = sdf.format(createTime);
			withdraw.setCreateTime(null);
		}
		LambdaQueryWrapper<BussinessUserWithdraw> lambda = Condition.getQueryWrapper(withdraw).lambda();
		lambda.like(createTime != null, BussinessUserWithdraw::getCreateTime, createTimeFormat);
		lambda.eq(BussinessUserWithdraw::getWithdrawStatus, SystemConstant.WithdrawOrderStatus.SUCCESS.getValue());
		List<BussinessUserWithdraw> list = baseMapper.selectList(lambda);
		BigDecimal stat = list.stream().map(item -> item.getOrderAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
		return stat;
	}

	@Override
	public R<WithdrawTransferOrder> initWithdrawOrder(BussinessUserWithdraw withdraw) {
		Long userInfoId = withdraw.getUserInfoId();
		BussinessUserInfo userInfo = userInfoService.getById(userInfoId);
		Assert.notNull(userInfo, "用户进件信息不存在");
		if(userInfo.getRegisterStatus().intValue() != SystemConstant.BussinessRegisterStatus.SUCCESS.getValue()){
			return R.fail("用户未完成进件审核");
		}
		Long bussinessId = userInfo.getBussinessId();
		Bussiness bussiness = this.bussinessService.getById(bussinessId);
		if(withdraw.getOrderAmount().compareTo(bussiness.getMaxLimit()) == 1){ //大于的时候返回1，等于返回0，小于返回-1
			log.error("=================代付请求前校验，提现金额不能超过商户每日限额=================");
			return R.fail("代付金额不能超过商户每日限额(限额 : 发起金额(不含手续费) = " + bussiness.getMaxLimit().toString() + ":" + String.valueOf(withdraw.getOrderAmount()) + ")");
		}else{
			//获取今日采购商已代付金额
			BusinessDeptDaliyStat todayStat = businessDeptDaliyStatService.getTodayStat(bussiness.getId());
			if(todayStat == null) {
				businessDeptDaliyStatService.createTodayStat(bussiness.getId(), null);
			}else{
				BigDecimal todayAmount = todayStat.getStatAmount();
				if(todayAmount.add(withdraw.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());
		String withdrawRate = paramService.getValue("yee_withdraw_rate");
		String transferRate = paramService.getValue("yee_transfer_rate");
		BigDecimal remain = bussinessRemainR.getData();
		BigDecimal orderAmount = withdraw.getOrderAmount();
		BigDecimal withdrawFee = new BigDecimal(withdrawRate);
		BigDecimal transferFee = new BigDecimal(transferRate);
		BigDecimal transferAmount = orderAmount.add(transferFee).add(withdrawFee); //这里包含实际提现金额，提现手续费以及帮平台商承担的转账手续费
		//如果余额小于订单金额+提现手续费+转账手续费*2，则认为不可以发起代付
		if(remain.compareTo(transferAmount.add(transferFee)) == -1){
			return R.fail("商户余额不足，无法发起代付。");
		}

		BussinessTransferOrder bussinessTransferOrder = new BussinessTransferOrder();
		bussinessTransferOrder.setFromMerchantNo(bussinessInfo.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_WITHDRAW_FIRST_TRANSFER.getValue());
		bussinessTransferOrder.setTransferStatus(SystemConstant.TransferOrderStatus.WAIT.getValue());
		boolean save = this.transferOrderService.save(bussinessTransferOrder);
		if(save){
			BussinessUserWithdraw withdrawOrder = this.createWithdrawOrder(userInfo, orderAmount, null, null);
			withdrawOrder.setFirstTransferOrderId(bussinessTransferOrder.getId());
			boolean save1 = this.save(withdrawOrder);
			if(save1){
				WithdrawTransferOrder withdrawTransferOrder = new WithdrawTransferOrder();
				withdrawTransferOrder.setTransferOrder(bussinessTransferOrder);
				withdrawTransferOrder.setWithdraw(withdrawOrder);
				return R.data(withdrawTransferOrder, "初始化订单成功");
			}else{
				return R.fail("初始化订单失败");
			}
		}else{
			return R.fail("初始化订单失败");
		}
	}

	@Override
	public List<WithdrawExcel> exportWithdraw(LambdaQueryWrapper<BussinessUserWithdraw> lambdaQueryWrapper) {
		List<BussinessUserWithdraw> list = this.list(lambdaQueryWrapper);
		List<WithdrawExcel> exportList = list.stream().map(item -> {
			WithdrawExcel excel = new WithdrawExcel();
			excel = BeanUtil.copy(item, WithdrawExcel.class);
			List<BankCode> bankCodeList = bankCodeService.getByBankCode(item.getBankCode());
			if (bankCodeList != null && bankCodeList.size() > 0) {
				BankCode bankCode = bankCodeList.get(0);
				excel.setBankName(bankCode.getName());
			}
			Integer withdrawStatus = item.getWithdrawStatus();
			excel.setWithdrawStatusTxt(SystemConstant.WithdrawOrderStatus.getNameByValue(withdrawStatus));
			return excel;
		}).collect(Collectors.toList());
		return exportList;
	}

	private BussinessUserWithdraw createWithdrawOrder(BussinessUserInfo userInfo, BigDecimal withdrawAmount, String failReason, String returnMsg){
		BussinessUserWithdraw withdraw = new BussinessUserWithdraw();
		withdraw.setUserInfoId(userInfo.getId());
		withdraw.setMerchantNo(userInfo.getMerchantNo());
		withdraw.setBankAccountNo(userInfo.getBankCardNo());
		withdraw.setOrderAmount(withdrawAmount);
		withdraw.setReceiveType("REAL_TIME");
		withdraw.setWithdrawStatus(SystemConstant.WithdrawOrderStatus.WAIT.getValue());
		withdraw.setFailReason(failReason);
		withdraw.setReturnMsg(returnMsg);
		withdraw.setRequestNo(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
		withdraw.setReceiverAccountName(userInfo.getUserName());
		withdraw.setBankCode(userInfo.getBankCode());
		return withdraw;
	}


}
