package com.ym.mec.biz.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.ym.mec.biz.dal.dao.GoodsProcurementDao;
import com.ym.mec.biz.dal.dao.HfMemberDao;
import com.ym.mec.biz.dal.dao.StudentPaymentRouteOrderDao;
import com.ym.mec.biz.dal.dao.SysConfigDao;
import com.ym.mec.biz.dal.dto.AmountChannelDto;
import com.ym.mec.biz.dal.dto.RouteScaleDto;
import com.ym.mec.biz.dal.entity.Goods;
import com.ym.mec.biz.dal.entity.GoodsProcurement;
import com.ym.mec.biz.dal.entity.HfMember;
import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
import com.ym.mec.biz.dal.entity.StudentPaymentOrderDetail;
import com.ym.mec.biz.dal.entity.StudentPaymentRouteOrder;
import com.ym.mec.biz.dal.entity.SysPaymentConfig;
import com.ym.mec.biz.dal.enums.FeeTypeEnum;
import com.ym.mec.biz.dal.enums.OrderDetailTypeEnum;
import com.ym.mec.biz.dal.enums.OrderTypeEnum;
import com.ym.mec.biz.dal.enums.PaymentChannelEnum;
import com.ym.mec.biz.service.GoodsService;
import com.ym.mec.biz.service.HfMerchantConfigService;
import com.ym.mec.biz.service.PayService;
import com.ym.mec.biz.service.SellOrderService;
import com.ym.mec.biz.service.StudentPaymentOrderDetailService;
import com.ym.mec.biz.service.StudentPaymentOrderService;
import com.ym.mec.biz.service.SysConfigService;
import com.ym.mec.biz.service.SysPaymentConfigService;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.redis.service.RedisCache;
import com.ym.mec.thirdparty.adapay.ConfigInit;
import com.ym.mec.thirdparty.adapay.Payment;
import com.ym.mec.thirdparty.adapay.entity.HfMerchantConfig;
import com.ym.mec.thirdparty.yqpay.YqPayUtil;
import com.ym.mec.util.date.DateUtil;

/**
 * 支付服务类
 */
@Service
public class PayServiceImpl implements PayService {
    @Autowired
    private StudentPaymentOrderService studentPaymentOrderService;
    
    @Autowired
    private StudentPaymentOrderDetailService studentPaymentOrderDetailService;
    
    @Autowired
    private GoodsService goodsService;
    
    @Autowired
    private HfMerchantConfigService hfMerchantConfigService;
    
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private SysPaymentConfigService sysPaymentConfigService;
    @Autowired
    private StudentPaymentRouteOrderDao studentPaymentRouteOrderDao;
    @Autowired
    private SellOrderService sellOrderService;
    @Autowired
    private HfMemberDao hfMemberDao;
    @Autowired
    private RedisCache<String, Object> redisCache;
    @Autowired
    private GoodsProcurementDao goodsProcurementDao;

    @Override
    public Map<String, Object> getPayMap(BigDecimal amount, BigDecimal balanceAmount, String orderNo, String notifyUrl, String returnUrl, String orderSubject, String orderBody, Integer organId, String receiver) throws Exception {

        StudentPaymentOrder studentPaymentOrder = studentPaymentOrderService.findOrderByOrderNo(orderNo);
        
        if(studentPaymentOrder == null){
        	throw new BizException("订单[{}]查询失败", orderNo);
        }
        
        Integer tenantId = studentPaymentOrder.getTenantId();
        
        HfMerchantConfig hfMerchantConfig = hfMerchantConfigService.queryByTenantId(tenantId);
        if(hfMerchantConfig == null){
        	throw new BizException("机构[{}]汇付商户信息找不到", tenantId);
        }
        
        if(tenantId != 1){//非大雅机构
        	
        	Date date = new Date();
        	
        	String merNo = "0";
        	
        	StudentPaymentRouteOrder studentPaymentRouteOrder = new StudentPaymentRouteOrder();
            studentPaymentRouteOrder.setOrderNo(orderNo);
            studentPaymentRouteOrder.setRouteOrganId(organId);
            studentPaymentRouteOrder.setFeeFlag("Y");
            studentPaymentRouteOrder.setRouteAmount(amount);
            studentPaymentRouteOrder.setRouteBalanceAmount(balanceAmount);
            studentPaymentRouteOrder.setMerNo(merNo);
            studentPaymentRouteOrder.setSaleAmount(BigDecimal.ZERO);
            studentPaymentRouteOrder.setServiceAmount(amount);
            studentPaymentRouteOrder.setTenantId(tenantId);
            studentPaymentRouteOrder.setCreateTime(date);
            studentPaymentRouteOrder.setUpdateTime(date);
            studentPaymentRouteOrderDao.insert(studentPaymentRouteOrder);
            
            Map<String, Object> unionPay = new HashMap<>();
            Map<String, Object> payMap = Payment.getPayMap(hfMerchantConfig, amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody);
            
            PaymentChannelEnum payType = PaymentChannelEnum.ADAPAY;

            unionPay.put("orderNo", orderNo);
            unionPay.put("type", payType.getCode());
            unionPay.put("payMap", payMap);
            unionPay.put("routingMerNos", merNo);
            return unionPay;
        }
        
		Date date = new Date();
        
        //如果当前是买的小课/网管课
		if (studentPaymentOrder != null && (studentPaymentOrder.getType() == OrderTypeEnum.SMALL_CLASS_TO_BUY || studentPaymentOrder.getType() == OrderTypeEnum.PRACTICE_GROUP_BUY
				|| studentPaymentOrder.getType() == OrderTypeEnum.PRACTICE_GROUP_RENEW)) {
			
			//忽略的分部
			List<Integer> ignoreOrganList = Arrays.asList(4);
			
			// 是否由平台收款
			String isPlatformCollection = sysConfigDao.findConfigValue(SysConfigService.IS_OPEN_SMALL_CLASS_INCOME_TO_PLATFORM);
			
			if (StringUtils.equals("1", isPlatformCollection) && !ignoreOrganList.contains(organId)) {
	        	
	        	String merNo = sysConfigDao.findConfigValue(SysConfigService.PLATFORM_PAYEE_ACCOUNT);
	        	
	        	if(StringUtils.isBlank(merNo)){
	        		throw new BizException("平台收款账户查询失败");
	        	}
	        	
	        	Integer routeOrganId = 68;
	        	
	        	StudentPaymentRouteOrder studentPaymentRouteOrder = new StudentPaymentRouteOrder();
	            studentPaymentRouteOrder.setOrderNo(orderNo);
	            studentPaymentRouteOrder.setRouteOrganId(routeOrganId);
	            studentPaymentRouteOrder.setFeeFlag("Y");
	            studentPaymentRouteOrder.setRouteAmount(amount);
	            studentPaymentRouteOrder.setRouteBalanceAmount(balanceAmount);
	            studentPaymentRouteOrder.setMerNo(merNo);
	            studentPaymentRouteOrder.setSaleAmount(BigDecimal.ZERO);
	            studentPaymentRouteOrder.setServiceAmount(amount);
	            studentPaymentRouteOrder.setTenantId(tenantId);
	            studentPaymentRouteOrder.setCreateTime(date);
	            studentPaymentRouteOrder.setUpdateTime(date);
	            studentPaymentRouteOrderDao.insert(studentPaymentRouteOrder);
	            
	            Map<String, Object> unionPay = new HashMap<>();
	            Map<String, Object> payMap = Payment.getPayMap(hfMerchantConfig, amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody);
	            
	            PaymentChannelEnum payType = PaymentChannelEnum.ADAPAY;

	            unionPay.put("orderNo", orderNo);
	            unionPay.put("type", payType.getCode());
	            unionPay.put("payMap", payMap);
	            unionPay.put("routingMerNos", merNo);
	            return unionPay;
			}
			
		}

		BigDecimal subBalance = BigDecimal.ZERO;
		
		BigDecimal subCashAmount = BigDecimal.ZERO;
		
		RouteScaleDto routeScaleDtoForGoodsSell = null;
    	//忽略的分部
		List<Integer> ignoreOrganList = Arrays.asList(4, 55, 59);
		
		//查询商品收款账户配置
        String goodsSellReceiptMerNo = sysConfigDao.findConfigValue("goodsSellReceiptMerNo");
        
        if(!ignoreOrganList.contains(organId) && StringUtils.isNotBlank(goodsSellReceiptMerNo)){
			
        	//根据商户号查询对应分部
        	SysPaymentConfig sysPaymentConfig = sysPaymentConfigService.findPaymentConfigByMerNo(StringUtils.trim(goodsSellReceiptMerNo));
        	
        	if(sysPaymentConfig != null){

    			List<StudentPaymentOrderDetail> batchUpdateList = new ArrayList<StudentPaymentOrderDetail>();
    			Map<Integer, Goods> batchUpdateGoodsMap = new HashMap<Integer, Goods>();
        		
        		// 如果买了商品或组合商品，商品有内部库存，则将钱转入指定账户已云教练的方式作为收费项目（杭州、齐齐哈尔除外）
        		// 1.查询商品订单明细
        		List<StudentPaymentOrderDetail> studentPaymentOrderDetailList = studentPaymentOrderDetailService.queryOrderDetail(studentPaymentOrder.getId());
        		if (studentPaymentOrderDetailList != null && studentPaymentOrderDetailList.size() > 0) {
        			
        			Map<Long, GoodsProcurement> goodsProcurementMap = new HashMap<Long, GoodsProcurement>();
        			
        			String goodIds = studentPaymentOrderDetailList.stream().filter(t -> StringUtils.isNotBlank(t.getGoodsIdList())).map(StudentPaymentOrderDetail :: getGoodsIdList).collect(Collectors.joining(","));
        			if(StringUtils.isNotBlank(goodIds)){
        				List<Goods> goodsList = goodsService.getGoodsWithLocked(goodIds);
        				
        				Map<Integer,Goods> goodsMap = goodsList.stream().collect(Collectors.toMap(Goods :: getId, t -> t));
        				Goods goods = null;
        				GoodsProcurement goodsProcurement = null;
        				BigDecimal totalAmout = studentPaymentOrder.getExpectAmount();
        				List<Integer> minuendStockGoodsIdList = null;
        				
        				for(StudentPaymentOrderDetail spod : studentPaymentOrderDetailList){
        					
        					if(StringUtils.isBlank(spod.getGoodsIdList())){
        						continue;
        					}
        					BigDecimal tempBalance = BigDecimal.ZERO;
        					
        					BigDecimal tempCashAmount = BigDecimal.ZERO;
        					
        					BigDecimal totalGroupPurchaseAmount = BigDecimal.ZERO;
        					
        					BigDecimal groupPurchaseAmount = BigDecimal.ZERO;
        					
        					minuendStockGoodsIdList = new ArrayList<Integer>();
        					
        					for(String goodsIdStr : spod.getGoodsIdList().split(",")){
        						if(StringUtils.isBlank(goodsIdStr)){
        							continue;
        						}
        						goods = goodsMap.get(Integer.parseInt(goodsIdStr));
        						
        						if(goods != null){
        							// 是否是组合商品
        							if(StringUtils.isNotBlank(goods.getComplementGoodsIdList())){
        								goodsList = goodsService.getGoodsWithLocked(goods.getComplementGoodsIdList());
        								totalGroupPurchaseAmount =  totalGroupPurchaseAmount.add(goodsList.stream().map(Goods :: getGroupPurchasePrice).reduce(BigDecimal.ZERO,BigDecimal :: add));
        								
        								for(Goods subGoods : goodsList){
    										
    										if(batchUpdateGoodsMap.get(subGoods.getId()) != null){
    											subGoods = batchUpdateGoodsMap.get(subGoods.getId());
    										}
        									//判断是否有内部库存
        									if(subGoods.getStockCount() > 0){
        										
        										groupPurchaseAmount = groupPurchaseAmount.add(subGoods.getGroupPurchasePrice());
        										subGoods.setStockCount(new AtomicInteger(subGoods.getStockCount()).decrementAndGet());
            									subGoods.setSellCount(new AtomicInteger(subGoods.getSellCount()).incrementAndGet());
        										subGoods.setUpdateTime(date);
        										
        										batchUpdateGoodsMap.put(subGoods.getId(), subGoods);
        										
        										minuendStockGoodsIdList.add(subGoods.getId());
        										
        										goodsProcurement = goodsProcurementDao.getWithStockSurplusProcurement(subGoods.getId());
        										if(goodsProcurement != null){
        											if(goodsProcurementMap.get(goodsProcurement.getId()) != null){
        												goodsProcurement = goodsProcurementMap.get(goodsProcurement.getId());
        											}
        											goodsProcurement.setStockSoldNum(new AtomicInteger(goodsProcurement.getStockSoldNum()).incrementAndGet());
        											goodsProcurement.setUpdateTime(date);
        											goodsProcurementMap.put(goodsProcurement.getId(), goodsProcurement);
        										}
        									}
        								}
        							}else{
    									totalGroupPurchaseAmount = totalGroupPurchaseAmount.add(goods.getGroupPurchasePrice());
    									
    									if(batchUpdateGoodsMap.get(goods.getId()) != null){
    										goods = batchUpdateGoodsMap.get(goods.getId());
										}
    									
        								//判断是否有内部库存
        								if(goods.getStockCount() > 0){
        									
    										groupPurchaseAmount = groupPurchaseAmount.add(goods.getGroupPurchasePrice());
    										goods.setStockCount(new AtomicInteger(goods.getStockCount()).decrementAndGet());
    										goods.setSellCount(new AtomicInteger(goods.getSellCount()).incrementAndGet());
    										goods.setUpdateTime(date);
    										batchUpdateGoodsMap.put(goods.getId(), goods);
    										
    										minuendStockGoodsIdList.add(goods.getId());
    										
    										goodsProcurement = goodsProcurementDao.getWithStockSurplusProcurement(goods.getId());
    										if(goodsProcurement != null){
    											if(goodsProcurementMap.get(goodsProcurement.getId()) != null){
    												goodsProcurement = goodsProcurementMap.get(goodsProcurement.getId());
    											}
    											goodsProcurement.setStockSoldNum(new AtomicInteger(goodsProcurement.getStockSoldNum()).incrementAndGet());
    											goodsProcurement.setUpdateTime(date);
    											goodsProcurementMap.put(goodsProcurement.getId(), goodsProcurement);
    										}
        								}
        							}
        						}
        					}
        					
							if (groupPurchaseAmount.compareTo(BigDecimal.ZERO) > 0) {
	        					// 3.是否使用余额
								if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
									/*tempBalance = balanceAmount.multiply(spod.getPrice()).divide(totalAmout).multiply(groupPurchaseAmount)
											.divide(totalGroupPurchaseAmount);*/
									tempBalance = balanceAmount.multiply(spod.getPrice()).multiply(groupPurchaseAmount)
											.divide(totalGroupPurchaseAmount.multiply(totalAmout), BigDecimal.ROUND_UP).setScale(2, BigDecimal.ROUND_UP);
									
									if(subBalance.add(tempBalance).compareTo(balanceAmount) > 0){
										tempBalance = balanceAmount.subtract(subBalance);
									}
									subBalance = subBalance.add(tempBalance);
								}
								// tempCashAmount = spod.getPrice().subtract(tempBalance).multiply(groupPurchaseAmount).divide(totalGroupPurchaseAmount, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
								tempCashAmount = amount.multiply(spod.getPrice()).multiply(groupPurchaseAmount)
										.divide(totalGroupPurchaseAmount.multiply(totalAmout), BigDecimal.ROUND_UP).setScale(2, BigDecimal.ROUND_UP);
								if(subCashAmount.add(tempCashAmount).compareTo(amount) > 0){
									tempCashAmount = amount.subtract(subCashAmount);
								}
								subCashAmount = subCashAmount.add(tempCashAmount);
								spod.setIncomeItem(OrderDetailTypeEnum.CLOUD_TEACHER.name());
								spod.setIncome(tempCashAmount);
								spod.setBalanceIncome(tempBalance);
								if(minuendStockGoodsIdList.size() > 0){
									spod.setMinuendStockGoodsIdList(minuendStockGoodsIdList.stream().map(t -> t.toString()).collect(Collectors.joining(",")));
								}
								batchUpdateList.add(spod);
							}
        				}
        			}
        			
        			if(goodsProcurementMap.size() > 0){
        				goodsProcurementDao.batchUpdate(new ArrayList<GoodsProcurement>(goodsProcurementMap.values()));
        			}
        		}
        		
        		if(batchUpdateList.size() > 0){
        			studentPaymentOrderDetailService.batchUpdate(batchUpdateList);
        		}
        		
        		if(batchUpdateGoodsMap.size() > 0){
        			goodsService.batchUpdate(new ArrayList<Goods>(batchUpdateGoodsMap.values()));
        		}
        		
        		if(subCashAmount.compareTo(BigDecimal.ZERO) > 0){
        			StudentPaymentRouteOrder studentPaymentRouteOrder = new StudentPaymentRouteOrder();
    	            studentPaymentRouteOrder.setOrderNo(orderNo);
    	            studentPaymentRouteOrder.setRouteOrganId(sysPaymentConfig.getOrganId());
    	            studentPaymentRouteOrder.setFeeFlag("Y");
    	            studentPaymentRouteOrder.setRouteAmount(subCashAmount);
    	            studentPaymentRouteOrder.setRouteBalanceAmount(subBalance);
    	            studentPaymentRouteOrder.setMerNo(goodsSellReceiptMerNo);
    	            studentPaymentRouteOrder.setSaleAmount(BigDecimal.ZERO);
    	            studentPaymentRouteOrder.setServiceAmount(subCashAmount);
    	            studentPaymentRouteOrder.setTenantId(tenantId);
    	            studentPaymentRouteOrder.setCreateTime(date);
    	            studentPaymentRouteOrder.setUpdateTime(date);
    	            studentPaymentRouteOrderDao.insert(studentPaymentRouteOrder);

    	            routeScaleDtoForGoodsSell = new RouteScaleDto();
    	            routeScaleDtoForGoodsSell.setAmount(subCashAmount);
    	            routeScaleDtoForGoodsSell.setBalance(subBalance);
    	            routeScaleDtoForGoodsSell.setOrganId(sysPaymentConfig.getOrganId());
    	            routeScaleDtoForGoodsSell.setPayType(PaymentChannelEnum.ADAPAY);
    	            routeScaleDtoForGoodsSell.setFeeType(FeeTypeEnum.SERVICE);
    	            routeScaleDtoForGoodsSell.setScale(100);
    	            routeScaleDtoForGoodsSell.setMerNo(goodsSellReceiptMerNo);
    	            routeScaleDtoForGoodsSell.setFeeFlag("Y");
        		}
        	}
        }
		
        if(amount.compareTo(subCashAmount) <= 0){
        	amount = BigDecimal.ZERO;
        }else{
        	amount = amount.subtract(subCashAmount);
        }
        if(balanceAmount.compareTo(subBalance) <= 0){
        	balanceAmount = BigDecimal.ZERO;
        }else{
        	balanceAmount = balanceAmount.subtract(subBalance);
        }
        
        String usePaymentConfig = sysConfigDao.findConfigValue("use_payment_config");// 是否用收费配置(1:使用 0:不使用)
        List<RouteScaleDto> routeScaleDtos = null;
        //使用配置开关
        if (usePaymentConfig.equals("0")) {
            routeScaleDtos = noUsePaymentConfig(amount); //款项都收到平台商户
        }

        //根据费用类型，mark
        if (routeScaleDtos == null) {
            routeScaleDtos = getTypeRouteChannel(organId, orderNo, amount, balanceAmount);
        }

        //根据金额获取分润
        if (routeScaleDtos == null) {
            routeScaleDtos = getAmountChannel(organId, amount, receiver);
        }
        //零星支付，收到指定
        if (routeScaleDtos == null) {
            routeScaleDtos = getSporadicChannel(amount, receiver);
        }
        //比例或者笔数分佣
        if (routeScaleDtos == null) {
            routeScaleDtos = getPaymentConfigChannel(organId, amount);
        }

        //验证最大收款金额
        for (RouteScaleDto routeScaleDto : routeScaleDtos) {
            checkMaxReceipt(routeScaleDto, routeScaleDto.getMerNo());
        }
        
        /*if(routeScaleDtoForGoodsSell != null){
        	routeScaleDtos.add(routeScaleDtoForGoodsSell);
        }*/
        
        Map<String, Object> map = getPayRoute(hfMerchantConfig, amount, balanceAmount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody, routeScaleDtos, subCashAmount);
        
		if (routeScaleDtoForGoodsSell != null) {
			String routingMerNos = (String) map.get("routingMerNos");
			
			List<String> list = new ArrayList<String>();
			if(StringUtils.isNotBlank(routingMerNos)){
				list = new ArrayList<String>(Arrays.asList(routingMerNos.split(",")));
			}
			if(!list.contains(routeScaleDtoForGoodsSell.getMerNo())){
				list.add(routeScaleDtoForGoodsSell.getMerNo());
			}

	        map.put("routingMerNos", String.join(",", list));
		}
        
        return map;
    }

    @Override
	public Map<String, Object> getPayToPlatformMap(Integer tenantId, PaymentChannelEnum paymentChannel, BigDecimal amount, BigDecimal balanceAmount, String orderNo, String notifyUrl, String returnUrl,
			String orderSubject, String orderBody) throws Exception {
    	
        HfMerchantConfig hfMerchantConfig = hfMerchantConfigService.queryByTenantId(tenantId);
        if(hfMerchantConfig == null){
        	throw new BizException("机构[{}]汇付商户信息找不到", tenantId);
        }
    	
        Map<String, Object> payMap = Payment.getPayMap(hfMerchantConfig, amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody);
        
        Map<String, Object> unionPay = new HashMap<>();
        unionPay.put("orderNo", orderNo);
        unionPay.put("type", paymentChannel.getCode());
        unionPay.put("payMap", payMap);
        unionPay.put("tenantId", hfMerchantConfig.getTenantId());
        unionPay.put("routingMerNos", hfMerchantConfig.getPlatformPayeeMemberId());
        
		return unionPay;
	}

	private List<RouteScaleDto> noUsePaymentConfig(BigDecimal amount) {
        String paymentChannel = sysConfigDao.findConfigValue("payment_channel");
        List<RouteScaleDto> routeScaleDtos = new ArrayList<>();
        RouteScaleDto routeScaleDto = new RouteScaleDto();
        routeScaleDto.setAmount(amount);
        routeScaleDto.setOrganId(ConfigInit.organId);
        routeScaleDto.setScale(100);
        if (paymentChannel.equals("YQPAY")) {
            routeScaleDto.setMerNo(YqPayUtil.merNo);
            routeScaleDto.setPayType(PaymentChannelEnum.YQPAY);
        } else {
            routeScaleDto.setMerNo(ConfigInit.merNo);
            routeScaleDto.setPayType(PaymentChannelEnum.ADAPAY);
        }
        routeScaleDto.setFeeFlag("Y");
        routeScaleDtos.add(routeScaleDto);
        return routeScaleDtos;
    }

    private List<RouteScaleDto> getPaymentConfigChannel(Integer organId, BigDecimal amount) {
        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);
        if (paymentConfig == null) {
            return noUsePaymentConfig(amount);
        }
        if (StringUtils.isBlank(paymentConfig.getRouteScale())) {
            List<RouteScaleDto> routeScaleDtos = new ArrayList<>();
            RouteScaleDto routeScaleDto = new RouteScaleDto();
            routeScaleDto.setAmount(amount);
            routeScaleDto.setOrganId(organId);
            routeScaleDto.setScale(100);
            routeScaleDto.setPayType(paymentConfig.getPayType());
            if (paymentConfig.getPayType().equals(PaymentChannelEnum.YQPAY)) {
                routeScaleDto.setMerNo(paymentConfig.getYqMerNo());
            } else {
                routeScaleDto.setMerNo(paymentConfig.getHfMerNo());
            }
            routeScaleDto.setFeeFlag("Y");
            routeScaleDtos.add(routeScaleDto);
            return routeScaleDtos;
        }

        String routeScale = paymentConfig.getRouteScale();
        List<RouteScaleDto> routeScaleDtos = JSON.parseArray(routeScale, RouteScaleDto.class);
        List<Integer> organIds = routeScaleDtos.stream().map(RouteScaleDto::getOrganId).collect(Collectors.toList());
        List<SysPaymentConfig> paymentConfigByOrganIds = sysPaymentConfigService.findPaymentConfigByOrganIds(organIds);
        for (RouteScaleDto routeScaleDto : routeScaleDtos) {
            routeScaleDto.setPayType(paymentConfig.getPayType());
            routeScaleDto.setAmount(amount);
            for (SysPaymentConfig paymentConfigByOrganId : paymentConfigByOrganIds) {
                if (!paymentConfigByOrganId.getOrganId().equals(routeScaleDto.getOrganId())) continue;
                if (paymentConfig.getPayType().equals(PaymentChannelEnum.YQPAY)) {
                    routeScaleDto.setMerNo(paymentConfigByOrganId.getYqMerNo());
                } else {
                    routeScaleDto.setMerNo(paymentConfigByOrganId.getHfMerNo());
                }
            }
        }

        //笔数比例
        if (paymentConfig.getType().equals(1)) {
            int payOrderNums = studentPaymentOrderService.findOrganPayOrderNum(organId); //获取支付中和成功的订单数
            int rem = payOrderNums % 10;
            rem = rem == 0 ? 10 : rem;

            int scale = 0;
            Iterator<RouteScaleDto> iterator = routeScaleDtos.iterator();
            while (iterator.hasNext()) {
                RouteScaleDto routeScaleDto = iterator.next();
                Integer num = routeScaleDto.getScale();
                boolean flag = false;
                if (rem > scale && rem <= scale + num) {
                    routeScaleDto.setScale(100);
                    flag = true;
                }
                scale += num;
                if (!flag) {
                    iterator.remove();
                }
            }
        }
        return routeScaleDtos;
    }


    /**
     * 根据金额获取渠道
     *
     * @param amount 金额
     */
    private List<RouteScaleDto> getAmountChannel(Integer organId, BigDecimal amount, String receiver) {
        String amountChannel = sysConfigDao.findConfigValue("amount_channel"); //按金额分润规则
        if (StringUtils.isBlank(amountChannel)) {
            return null;
        }
        Set<String> musicGroupType = new HashSet<>();
        musicGroupType.add("renew");
        musicGroupType.add("register");
        if (musicGroupType.contains(receiver)) {
            receiver = "musicGroupBuy";
        }

        Integer routeOrganId = null;
        List<AmountChannelDto> amountChannelDtoList = JSON.parseArray(amountChannel, AmountChannelDto.class);
        for (AmountChannelDto amountChannelDto : amountChannelDtoList) {
            if (amountChannelDto.getOrganId().equals(organId) &&
                    //0的时候不限定金额
                    (amountChannelDto.getAmount().compareTo(BigDecimal.ZERO) == 0 || amount.compareTo(amountChannelDto.getAmount()) == 0) &&
                    receiver.equals(amountChannelDto.getType())
            ) {
                routeOrganId = amountChannelDto.getRouteOrganId();
                break;
            }
        }

        if (routeOrganId == null) {
            return null;
        }

        //调度到 鎏逸乐器经营部 检测限定金额
        if (checkHasMaxReceipt(routeOrganId, amount)) {
            return null;
        }

        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(routeOrganId);

        RouteScaleDto routeScaleDto = new RouteScaleDto();
        List<RouteScaleDto> routeScaleDtos = new ArrayList<>();
        routeScaleDto.setAmount(amount);
        routeScaleDto.setOrganId(paymentConfig.getOrganId());
        routeScaleDto.setPayType(paymentConfig.getPayType());
        routeScaleDto.setScale(100);
        if (paymentConfig.getPayType().equals(PaymentChannelEnum.YQPAY)) {
            routeScaleDto.setMerNo(paymentConfig.getYqMerNo());
        } else {
            routeScaleDto.setMerNo(paymentConfig.getHfMerNo());
        }
        routeScaleDto.setFeeFlag("Y");
        routeScaleDtos.add(routeScaleDto);
        return routeScaleDtos;
    }

    /**
     * 零星支付获取渠道
     *
     * @param amount
     * @return
     */
    private List<RouteScaleDto> getSporadicChannel(BigDecimal amount, String receiver) {
        if (receiver == null || !receiver.equals("sporadic")) {
            return null;
        }
        String SporadicChannel = sysConfigDao.findConfigValue("sporadic_channel"); // 零星支付收款规则
        if (StringUtils.isBlank(SporadicChannel)) {
            return null;
        }

        Map<String, Object> channel = (Map<String, Object>) JSON.parseObject(SporadicChannel, Map.class);

        BigDecimal minReceiptMoney = new BigDecimal(channel.get("minReceipt").toString()); //最小接收的金额(不包含)
        if (amount.compareTo(minReceiptMoney) <= 0) {
            return null;
        }

        Integer organId = Integer.parseInt(channel.get("organId").toString());
        if (checkHasMaxReceipt(organId, amount)) {
            return null;
        }

        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);

        RouteScaleDto routeScaleDto = new RouteScaleDto();
        List<RouteScaleDto> routeScaleDtos = new ArrayList<>();
        routeScaleDto.setAmount(amount);
        routeScaleDto.setOrganId(paymentConfig.getOrganId());
        routeScaleDto.setPayType(paymentConfig.getPayType());
        routeScaleDto.setScale(100);
        if (paymentConfig.getPayType().equals(PaymentChannelEnum.YQPAY)) {
            routeScaleDto.setMerNo(paymentConfig.getYqMerNo());
        } else {
            routeScaleDto.setMerNo(paymentConfig.getHfMerNo());
        }
        routeScaleDto.setFeeFlag("Y");
        routeScaleDtos.add(routeScaleDto);
        return routeScaleDtos;
    }

    //按金额和零星支付（调度到 鎏逸乐器经营部 检测限定金额）
    private Boolean checkHasMaxReceipt(Integer organId, BigDecimal amount) {
        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);

        if (!paymentConfig.getHfMerNo().equals("H004217")) {
            return false;
        }
        BigDecimal monthMaxReceipt = new BigDecimal(75000); //每月限定金额
        BigDecimal totalMaxReceipt = new BigDecimal(5000000); //总限定金额（500W）

        Date monthStartTime = DateUtil.getFirstDayOfMonth(new Date());

        //已收金额
        List<PaymentChannelEnum> paymentChannelList = new ArrayList<>();
        paymentChannelList.add(PaymentChannelEnum.YQPAY);
        paymentChannelList.add(PaymentChannelEnum.ADAPAY);

        BigDecimal monthHasReceipt = studentPaymentRouteOrderDao.getRouteOrderAmount(organId, paymentChannelList, monthStartTime);
        monthHasReceipt = monthHasReceipt == null ? BigDecimal.ZERO : monthHasReceipt;
        if (amount.add(monthHasReceipt).compareTo(monthMaxReceipt) >= 0) {
            return true;
        }
        BigDecimal totalHasReceipt = studentPaymentRouteOrderDao.getRouteOrderAmount(organId, paymentChannelList, null);
        totalHasReceipt = totalHasReceipt == null ? BigDecimal.ZERO : totalHasReceipt;
        return amount.add(totalHasReceipt).compareTo(totalMaxReceipt) >= 0;
    }

    private Map<String, Object> getPayRoute(HfMerchantConfig hfMerchantConfig, BigDecimal amount, BigDecimal balanceAmount, String orderNo, String notifyUrl, String returnUrl, String orderSubject, String orderBody, List<RouteScaleDto> routeScaleDtos, BigDecimal shareAmount) throws Exception {
        Map<String, List<RouteScaleDto>> routeScaleDtosMap = routeScaleDtos.stream().collect(Collectors.groupingBy(RouteScaleDto::getMerNo));

        //合并同账号的数据
        List<RouteScaleDto> newRouteScaleDtos = new ArrayList<>();
        for (Map.Entry<String, List<RouteScaleDto>> groupRouteScaleDtos : routeScaleDtosMap.entrySet()) {
            RouteScaleDto routeScaleDto = null;
            for (RouteScaleDto scaleDto : groupRouteScaleDtos.getValue()) {
                if (routeScaleDto == null) {
                    routeScaleDto = scaleDto;
                } else {
                    routeScaleDto.setAmount(routeScaleDto.getAmount().add(scaleDto.getAmount()));
                    routeScaleDto.setBalance(routeScaleDto.getBalance().add(scaleDto.getBalance()));
                    routeScaleDto.setSaleAmount(routeScaleDto.getSaleAmount().add(scaleDto.getSaleAmount()));
                    routeScaleDto.setServiceAmount(routeScaleDto.getServiceAmount().add(scaleDto.getServiceAmount()));
                }
            }
            newRouteScaleDtos.add(routeScaleDto);
        }
        routeScaleDtos = newRouteScaleDtos;

        Map<String, Object> unionPay = new HashMap<>();
        Map<String, Object> payMap = null;

        List<StudentPaymentRouteOrder> RouteOrders = new ArrayList<>();

        BigDecimal yqAmount = amount.subtract((amount.multiply(new BigDecimal("0.28")).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP)));
        int i = 0;
        BigDecimal hasRouteAmount = BigDecimal.ZERO;
        BigDecimal hasRouteBalanceAmount = BigDecimal.ZERO;
        BigDecimal hasRouteMoney = BigDecimal.ZERO;
        List<Map<String, Object>> tempRoutingList = new ArrayList<>();

        PaymentChannelEnum payType = null;
        Set<String> routingMerNoSet = new HashSet<>();
        for (RouteScaleDto routeScaleDto : routeScaleDtos) {
            payType = routeScaleDto.getPayType();
            Map<String, Object> routingList = new HashMap<>();
            i++;

            BigDecimal routingAmount = amount;
            if (routeScaleDto.getPayType().equals(PaymentChannelEnum.YQPAY)) {
                routingAmount = yqAmount;
            }

            BigDecimal routingFee = null;
            BigDecimal routeBalanceAmount = null;
            BigDecimal routingMoney = null;

            if (routeScaleDto.getFeeType() == null) {
                routingFee = routingAmount.multiply(new BigDecimal(routeScaleDto.getScale())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
                routeBalanceAmount = balanceAmount.multiply(new BigDecimal(routeScaleDto.getScale())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
                routingMoney = amount.multiply(new BigDecimal(routeScaleDto.getScale())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
            } else {
                routingFee = routeScaleDto.getAmount();
                routeBalanceAmount = routeScaleDto.getBalance();
                routingMoney = routeScaleDto.getAmount();
            }
            if (i == routeScaleDtos.size()) {
                routingFee = routingAmount.subtract(hasRouteAmount).setScale(2, BigDecimal.ROUND_HALF_UP);
                routeBalanceAmount = balanceAmount.subtract(hasRouteBalanceAmount).setScale(2, BigDecimal.ROUND_HALF_UP);
                routingMoney = amount.subtract(hasRouteMoney).setScale(2, BigDecimal.ROUND_HALF_UP);
            }

            if (routingMoney.compareTo(BigDecimal.ZERO) <= 0 && routeBalanceAmount.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }

            hasRouteAmount = hasRouteAmount.add(routingFee);
            hasRouteBalanceAmount = hasRouteBalanceAmount.add(routeBalanceAmount);
            hasRouteMoney = hasRouteMoney.add(routingMoney);

            routingList.put("routingMerNo", routeScaleDto.getMerNo());//分佣账户
            routingList.put("routingFee", routingFee); //分佣金额
            tempRoutingList.add(routingList);

            //ADAPAY 采用延迟分账模式，手续费各自承担(2021-01-01号正式执行)
            if (routeScaleDto.getPayType().equals(PaymentChannelEnum.ADAPAY)) {
                routeScaleDto.setFeeFlag("Y");
            }

            StudentPaymentRouteOrder studentPaymentRouteOrder = new StudentPaymentRouteOrder();
            studentPaymentRouteOrder.setOrderNo(orderNo);
            studentPaymentRouteOrder.setRouteOrganId(routeScaleDto.getOrganId());
            studentPaymentRouteOrder.setFeeFlag(routeScaleDto.getFeeFlag());
            studentPaymentRouteOrder.setRouteAmount(routingMoney);
            studentPaymentRouteOrder.setRouteBalanceAmount(routeBalanceAmount);
            studentPaymentRouteOrder.setMerNo(routeScaleDto.getMerNo());
            studentPaymentRouteOrder.setSaleAmount(routeScaleDto.getSaleAmount());
            studentPaymentRouteOrder.setServiceAmount(routeScaleDto.getServiceAmount());
            studentPaymentRouteOrder.setTenantId(hfMerchantConfig.getTenantId());
            RouteOrders.add(studentPaymentRouteOrder);
            routingMerNoSet.add(routeScaleDto.getMerNo());
        }

        if(RouteOrders.size() > 0) {
	        if (studentPaymentRouteOrderDao.batchAdd(RouteOrders) <= 0) {
	            throw new BizException("调用支付接口失败");
	        }
        }

        if (payType.equals(PaymentChannelEnum.YQPAY)) {
            if (tempRoutingList.size() == 1 && YqPayUtil.merNo.equals(tempRoutingList.get(0).get("routingMerNo").toString())) {
                tempRoutingList = null;
            }
            payMap = YqPayUtil.getPayMap(amount.add(shareAmount), orderNo, notifyUrl, returnUrl, orderSubject, orderBody, YqPayUtil.merNo, tempRoutingList);
        } else {
            payMap = Payment.getPayMap(hfMerchantConfig, amount.add(shareAmount), orderNo, notifyUrl, returnUrl, orderSubject, orderBody);
        }
        String routingMerNos = String.join(",", routingMerNoSet);

        unionPay.put("orderNo", orderNo);
        unionPay.put("type", payType.getCode());
        unionPay.put("payMap", payMap);
        unionPay.put("routingMerNos", routingMerNos);
        return unionPay;
    }

    /**
     * @param organId
     * @param orderNo
     * @param amount
     * @return
     */
    private List<RouteScaleDto> getTypeRouteChannel(Integer organId, String orderNo, BigDecimal amount, BigDecimal balanceAmount) {
        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);
        if (paymentConfig == null || StringUtils.isBlank(paymentConfig.getTypeRouteScale())) {
            return null;
        }

        Map<String, BigDecimal> sellAmount = sellOrderService.getSellAmount(orderNo);
        if (sellAmount == null) {
            return null;
        }

        String typeRouteScale = paymentConfig.getTypeRouteScale();
        List<RouteScaleDto> routeScaleDtos = JSON.parseArray(typeRouteScale, RouteScaleDto.class);
        List<Integer> organIds = routeScaleDtos.stream().map(RouteScaleDto::getOrganId).collect(Collectors.toList());
        List<SysPaymentConfig> paymentConfigByOrganIds = sysPaymentConfigService.findPaymentConfigByOrganIds(organIds);

        long serviceCount = routeScaleDtos.stream().filter(e -> e.getFeeType().equals(FeeTypeEnum.SERVICE)).count();
        long sellCount = routeScaleDtos.stream().filter(e -> e.getFeeType().equals(FeeTypeEnum.SELL)).count();

        BigDecimal routeAmount = sellAmount.get("actualAmount");
        BigDecimal routeBalance = sellAmount.get("balance");

        BigDecimal serviceHasRouteMoney = BigDecimal.ZERO;
        BigDecimal serviceHasRouteBalance = BigDecimal.ZERO;
        BigDecimal sellHasRouteMoney = BigDecimal.ZERO;
        BigDecimal sellHasRouteBalance = BigDecimal.ZERO;

        Iterator<RouteScaleDto> iterator = routeScaleDtos.iterator();
        while (iterator.hasNext()) {
            RouteScaleDto routeScaleDto = iterator.next();
            routeScaleDto.setPayType(paymentConfig.getPayType());
            if (routeScaleDto.getFeeType().equals(FeeTypeEnum.SERVICE)) {
                routeAmount = amount.subtract(sellAmount.get("actualAmount"));
                routeBalance = balanceAmount.subtract(sellAmount.get("balance"));
                serviceCount--;
            } else {
                routeAmount = sellAmount.get("actualAmount");
                routeBalance = sellAmount.get("balance");
                sellCount--;
            }

            BigDecimal routingMoney = routeAmount.multiply(new BigDecimal(routeScaleDto.getScale())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
            BigDecimal routingBalance = routeBalance.multiply(new BigDecimal(routeScaleDto.getScale())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);

            if (routeScaleDto.getFeeType().equals(FeeTypeEnum.SERVICE) && serviceCount == 0) {
                routingMoney = routeAmount.subtract(serviceHasRouteMoney);
                routingBalance = routeBalance.subtract(serviceHasRouteBalance);
            } else if (routeScaleDto.getFeeType().equals(FeeTypeEnum.SELL) && sellCount == 0) {
                routingMoney = routeAmount.subtract(sellHasRouteMoney);
                routingBalance = routeBalance.subtract(sellHasRouteBalance);
            }
            routeScaleDto.setAmount(routingMoney);
            routeScaleDto.setBalance(routingBalance);

            if (routeScaleDto.getFeeType().equals(FeeTypeEnum.SERVICE)) {
                serviceHasRouteMoney = serviceHasRouteMoney.add(routingMoney);
                serviceHasRouteBalance = serviceHasRouteBalance.add(routingBalance);
                routeScaleDto.setServiceAmount(routingMoney);
            } else {
                sellHasRouteMoney = sellHasRouteMoney.add(routingMoney);
                sellHasRouteBalance = sellHasRouteBalance.add(routingBalance);
                routeScaleDto.setSaleAmount(routingMoney);
            }

            /*if (routeScaleDto.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                iterator.remove();
                continue;
            }*/

            for (SysPaymentConfig paymentConfigByOrganId : paymentConfigByOrganIds) {
                if (!paymentConfigByOrganId.getOrganId().equals(routeScaleDto.getOrganId())) continue;
                if (paymentConfig.getPayType().equals(PaymentChannelEnum.YQPAY)) {
                    routeScaleDto.setMerNo(paymentConfigByOrganId.getYqMerNo());
                } else {
                    routeScaleDto.setMerNo(paymentConfigByOrganId.getHfMerNo());
                }
            }
        }
        Map<String, List<RouteScaleDto>> routeScaleDtosMap = routeScaleDtos.stream().collect(Collectors.groupingBy(RouteScaleDto::getMerNo));

        //合并同账号的数据
        List<RouteScaleDto> newRouteScaleDtos = new ArrayList<>();
        for (Map.Entry<String, List<RouteScaleDto>> groupRouteScaleDtos : routeScaleDtosMap.entrySet()) {
            RouteScaleDto routeScaleDto = null;
            for (RouteScaleDto scaleDto : groupRouteScaleDtos.getValue()) {
                if (routeScaleDto == null) {
                    routeScaleDto = scaleDto;
                } else {
                    routeScaleDto.setAmount(routeScaleDto.getAmount().add(scaleDto.getAmount()));
                    routeScaleDto.setBalance(routeScaleDto.getBalance().add(scaleDto.getBalance()));
                    routeScaleDto.setSaleAmount(routeScaleDto.getSaleAmount().add(scaleDto.getSaleAmount()));
                    routeScaleDto.setServiceAmount(routeScaleDto.getServiceAmount().add(scaleDto.getServiceAmount()));
                }
            }
            newRouteScaleDtos.add(routeScaleDto);
        }
        return newRouteScaleDtos;
    }


    /**
     * 收款已满转到其他收款账户
     *
     * @param routeScaleDto
     * @param merNo
     * @return
     */
    private RouteScaleDto checkMaxReceipt(RouteScaleDto routeScaleDto, String merNo) {
        HfMember hfmember = hfMemberDao.getByMemberId(routeScaleDto.getMerNo());
        if (hfmember == null || hfmember.getMonthMaxReceipt().compareTo(BigDecimal.ZERO) <= 0) {
            return routeScaleDto;
        }

        BigDecimal monthMaxReceipt = hfmember.getMonthMaxReceipt(); //每月限定金额
        Date dayStartTime = DateUtil.trunc(new Date());

        //已收金额
        List<PaymentChannelEnum> paymentChannelList = new ArrayList<>();
        paymentChannelList.add(PaymentChannelEnum.ADAPAY);

//        String key = "month_max_receipt_"+routeScaleDto.getOrganId();
//        if(redisCache.exists(key)){
//            RedisTemplate<String, Object> redisTemplate = redisCache.getRedisTemplate();
//            try {
//                ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
//                Long index = valueOper.increment(key, 1);
//            } catch (Exception ex) {
//                log.error("分布式订单号生成失败异常。。。。。", ex);
//            } finally {
//                redisTemplate.expire(key, 600, TimeUnit.SECONDS);// 保留10分钟内的key
//            }
//        }else {
        BigDecimal monthHasReceipt = studentPaymentRouteOrderDao.getRouteOrderAmount(routeScaleDto.getOrganId(), paymentChannelList, dayStartTime);
        monthHasReceipt = monthHasReceipt == null ? BigDecimal.ZERO : monthHasReceipt;
//            monthHasReceipt.multiply(new BigDecimal(100));
//
//        }


        if (routeScaleDto.getAmount().add(monthHasReceipt).compareTo(monthMaxReceipt) > 0) {
            routeScaleDto.setMerNo(hfmember.getRouteMemberId());
            routeScaleDto.setOrganId(hfmember.getRouteOrganId());
            if (routeScaleDto.getMerNo().equals(merNo)) {
                return routeScaleDto;
            }
            return checkMaxReceipt(routeScaleDto, merNo);
        }
        return routeScaleDto;
    }
}
