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

import com.ym.mec.biz.dal.dao.MusicGroupDao;
import com.ym.mec.biz.dal.dao.SysConfigDao;
import com.ym.mec.biz.dal.entity.CooperationOrgan;
import com.ym.mec.biz.dal.entity.MusicGroup;
import com.ym.mec.biz.dal.entity.SysAccount;
import com.ym.mec.biz.dal.entity.SysPaymentConfig;
import com.ym.mec.biz.dal.enums.PaymentChannelTypeEnum;
import com.ym.mec.biz.service.PayService;
import com.ym.mec.biz.service.StudentPaymentOrderService;
import com.ym.mec.biz.service.SysAccountService;
import com.ym.mec.biz.service.SysPaymentConfigService;
import com.ym.mec.thirdparty.adapay.Pay;
import com.ym.mec.thirdparty.union.UnionPay;
import com.ym.mec.thirdparty.union.UnionPayFeignService;
import com.ym.mec.thirdparty.yqpay.YqPayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 支付服务类
 */
@Service
public class PayServiceImpl implements PayService {

    @Autowired
    private UnionPayFeignService unionPayFeignService;
    @Autowired
    private StudentPaymentOrderService studentPaymentOrderService;
    @Autowired
    private SysAccountService sysAccountService;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private SysPaymentConfigService sysPaymentConfigService;


    /**
     * 返回订单提交数据
     *
     * @param amount       金额
     * @param orderNo      订单编号
     * @param notifyUrl    异步通知地址
     * @param returnUrl    支付返回地址
     * @param orderSubject 订单标题
     * @param orderBody    订单内容
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> getPayMap(BigDecimal amount, String orderNo, String notifyUrl, String returnUrl, String orderSubject, String orderBody, Integer userId) throws Exception {

        String company = "daya";
        if (userId != null) {
            MusicGroup musicGroup = musicGroupDao.findUserMusicGroup(userId);
            if (musicGroup != null && musicGroup.getOwnershipType().equals(CooperationOrgan.OwnershipType.COOPERATION)) {
                company = "yaming";
            }
        }

        //支付通道决策
        Map<String, Object> unionPay = new HashMap<>();
        SysAccount routingAccount = getRoutingAccount(company, amount);
        PaymentChannelTypeEnum paymentChannelType = PaymentChannelTypeEnum.COM;
        if (routingAccount.getType().equals("PER")) {
            paymentChannelType = PaymentChannelTypeEnum.PER;
        }
        Map<String, Object> payMap = null;
        String type = null;
        if (routingAccount.getChannel().equals("YQPAY")) {
            payMap = YqPayUtil.getPayMap(amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody, routingAccount.getMerNo(), routingAccount.getRoutingMerNo());
            type = "YQPAY";
        } else {
            payMap = new Pay().getPayMap(amount, orderNo, notifyUrl, orderSubject, orderBody);
            type = "ADAPAY";
        }

        unionPay.put("orderNo", orderNo);
        unionPay.put("type", type);
        unionPay.put("paymentChannelType", paymentChannelType);
        unionPay.put("payMap", payMap);
        return unionPay;
    }

    @Override
    public Map<String, Object> getPayMap(BigDecimal amount, String orderNo, String notifyUrl, String returnUrl, String orderSubject, String orderBody, Integer userId, Map<String, BigDecimal> fee, Integer organId) throws Exception {
        String company = "daya";
        if (userId != null) {
            MusicGroup musicGroup = musicGroupDao.findUserMusicGroup(userId);
            if (musicGroup != null && musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType().equals(CooperationOrgan.OwnershipType.COOPERATION)) {
                company = "yaming";
            }
        }
        //深圳，广州，上海分部收到深圳大雅
        Set<Integer> organIds = new HashSet<>();
        organIds.add(16);
        organIds.add(3);
        organIds.add(15);
        if(organIds.contains(organId)){
            company = "sdaya";
        }

        //支付通道决策
        Map<String, Object> unionPay = new HashMap<>();
        Map<String, BigDecimal> routingFee = getRoutingFee(company, amount, fee, organId);
        List<SysAccount> accounts = getRoutingAccount(routingFee, company);
        SysAccount routingAccount = accounts.get(0);

        Map<String, Object> payMap = null;
        String type = null;
        if (routingAccount.getChannel().equals("YQPAY")) {
            List<Map<String, Object>> tempRoutingList = new ArrayList();
            for (SysAccount account : accounts) {
                Map<String, Object> routingList = new HashMap<>();
                routingList.put("routingMerNo", account.getRoutingMerNo());//分佣账户
                routingList.put("routingFee", account.getRoutingFee().subtract((account.getRoutingFee().multiply(new BigDecimal("0.28")).divide(new BigDecimal(100))).setScale(2, BigDecimal.ROUND_HALF_UP))); //分佣金额
                tempRoutingList.add(routingList);
            }
            if (accounts.size() == 1 && routingAccount.getMerNo().equals(routingAccount.getRoutingMerNo())) {
                tempRoutingList = null;
            }

            payMap = YqPayUtil.getPayMap(amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody, routingAccount.getMerNo(), tempRoutingList);
            type = "YQPAY";
        } else {
            payMap = new Pay().getPayMap(amount, orderNo, notifyUrl, orderSubject, orderBody);
            type = "ADAPAY";
        }

        String routingMerNos = accounts.stream().map(sysAccount -> sysAccount.getRoutingMerNo()).collect(Collectors.joining(","));

        unionPay.put("orderNo", orderNo);
        unionPay.put("type", type);
        unionPay.put("payMap", payMap);
        unionPay.put("routingFee", routingFee);
        unionPay.put("routingMerNos", routingMerNos);
        unionPay.put("routingOrganId", accounts.get(0).getRoutingOrganId());
        return unionPay;
    }

    @Override
    public Map<String, Object> getPayMap(BigDecimal amount, String orderNo, String notifyUrl, String returnUrl, String orderSubject, String orderBody, Integer userId, Map<String, BigDecimal> fee, Integer organId, String receiver) throws Exception {
        String company = "daya";
        if (userId != null) {
            MusicGroup musicGroup = musicGroupDao.findUserMusicGroup(userId);
            if (musicGroup != null && musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType().equals(CooperationOrgan.OwnershipType.COOPERATION)) {
                company = "yaming";
            }
        }
        if (receiver.equals("sdaya")) {
            company = "sdaya";
            receiver = null;
        }

        //支付通道决策
        Map<String, Object> unionPay = new HashMap<>();
        Map<String, BigDecimal> routingFee = getRoutingFee(company, amount, fee, organId, receiver);
        List<SysAccount> accounts = getRoutingAccount(routingFee, company);
        SysAccount routingAccount = accounts.get(0);

        Map<String, Object> payMap = null;
        String type = null;
        if (routingAccount.getChannel().equals("YQPAY")) {
            List<Map<String, Object>> tempRoutingList = new ArrayList();
            for (SysAccount account : accounts) {
                Map<String, Object> routingList = new HashMap<>();
                routingList.put("routingMerNo", account.getRoutingMerNo());//分佣账户
                routingList.put("routingFee", account.getRoutingFee().subtract((account.getRoutingFee().multiply(new BigDecimal("0.28")).divide(new BigDecimal(100))).setScale(2, BigDecimal.ROUND_HALF_UP))); //分佣金额
                tempRoutingList.add(routingList);
            }
            if (accounts.size() == 1 && routingAccount.getMerNo().equals(routingAccount.getRoutingMerNo())) {
                tempRoutingList = null;
            }

            payMap = YqPayUtil.getPayMap(amount, orderNo, notifyUrl, returnUrl, orderSubject, orderBody, routingAccount.getMerNo(), tempRoutingList);
            type = "YQPAY";
        } else {
            payMap = new Pay().getPayMap(amount, orderNo, notifyUrl, orderSubject, orderBody);
            type = "ADAPAY";
        }

        String routingMerNos = accounts.stream().map(sysAccount -> sysAccount.getRoutingMerNo()).collect(Collectors.joining(","));

        unionPay.put("orderNo", orderNo);
        unionPay.put("type", type);
        unionPay.put("payMap", payMap);
        unionPay.put("routingFee", routingFee);
        unionPay.put("routingMerNos", routingMerNos);
        unionPay.put("routingOrganId", accounts.get(0).getRoutingOrganId());
        return unionPay;
    }

    @Override
    public Map<String, Object> query(String orderNo) throws Exception {
        return new UnionPay(unionPayFeignService).query(orderNo);
    }

    /**
     * 获取收款账户
     *
     * @param company
     * @param money
     * @return
     */
    private SysAccount getRoutingAccount(String company, BigDecimal money) {
        SysAccount routingAccount = null;
        int payOrderNums = studentPaymentOrderService.findPayOrderNum(); //获取支付中和成功的订单数
        //前几笔收入私户
        int nums = Integer.parseInt(sysConfigDao.findConfigValue("per_account_nums"));

        String type = null;
        String channel = null;
        int rem = (payOrderNums + 1) % 10;
        if (rem > 0 && rem <= nums) { //私人账户
            channel = sysConfigDao.findConfigValue("per_account_channel");
            type = "PER";
        } else {
            channel = sysConfigDao.findConfigValue("com_account_channel");
            type = "COM";
        }
        if (company.equals("yaming")) {
            type = "PER";
        }
        SysAccount account = sysAccountService.getOneAccount(company, channel, type, null);

        return account;
    }

    /**
     * 获取收款账户
     *
     * @param routingFee
     * @param company
     * @return
     */
    private List<SysAccount> getRoutingAccount(Map<String, BigDecimal> routingFee, String company) {
        String channel = "";
        String type = "";

        if (routingFee.get("COM").compareTo(BigDecimal.ZERO) > 0 && routingFee.get("PER").compareTo(BigDecimal.ZERO) > 0) {
            channel = "YQPAY";
            type = "COM,PER";
        } else if (routingFee.get("COM").compareTo(BigDecimal.ZERO) > 0 && routingFee.get("PER").compareTo(BigDecimal.ZERO) == 0) {
            channel = sysConfigDao.findConfigValue("com_account_channel");
            type = "COM";
        } else if (routingFee.get("COM").compareTo(BigDecimal.ZERO) == 0 && routingFee.get("PER").compareTo(BigDecimal.ZERO) > 0) {
            channel = sysConfigDao.findConfigValue("per_account_channel");
            type = "PER";
        }
        List<SysAccount> accounts = sysAccountService.getAccount(company, channel, type, null);

        for (SysAccount account : accounts) {
            if (account.getType().equals("COM")) {
                account.setRoutingFee(routingFee.get("COM"));
            } else {
                //私有账户根据金额切换账户
//                SysAccount perAccount = sysAccountService.getPerAccount(channel, account);
//                if (perAccount != null) {
//                    account.setRoutingMerNo(perAccount.getRoutingMerNo());
//                    if (!account.getCompany().equals("daya")) {
//                        account.setMerNo(perAccount.getRoutingMerNo());
//                    }
//                }
                account.setRoutingFee(routingFee.get("PER"));
            }
        }
        return accounts;
    }

    /**
     * 获取分佣金额
     *
     * @param fee
     * @param organId
     * @return
     */
    private Map<String, BigDecimal> getRoutingFee(String company, BigDecimal amount, Map<String, BigDecimal> fee, Integer organId) {
        Map<String, BigDecimal> routingFee = new HashMap<>(2);
        routingFee.put("COM", BigDecimal.ZERO);
        routingFee.put("PER", BigDecimal.ZERO);
        if (company.equals("yaming")) {
            routingFee.put("PER", amount);
            return routingFee;
        }

        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);

        int payOrderNums = studentPaymentOrderService.findPayOrderNum(); //获取支付中和成功的订单数
        //前几笔收入私户
        Integer nums = Integer.parseInt(sysConfigDao.findConfigValue("per_account_nums"));
        if (paymentConfig != null && paymentConfig.getType().equals(1)) {
            nums = paymentConfig.getPerScale();
        }

        String type = null;
        int rem = (payOrderNums + 1) % 10;
        if (rem > 0 && rem <= nums) { //私人账户
            type = "PER";
        } else {
            type = "COM";
        }
        routingFee.put(type, amount);

        if (paymentConfig == null || !paymentConfig.getType().equals(2)) {
            return routingFee;
        }
        routingFee.put(type, BigDecimal.ZERO);
        for (Map.Entry<String, BigDecimal> feeEntry : fee.entrySet()) {
            if (feeEntry.getKey().equals("course")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getCourseFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getCourseFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("instrument")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getInstrumentFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getInstrumentFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("accessories")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getAccessoriesFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getAccessoriesFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("other")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getOtherFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getOtherFee(), RoutingFee);
            }
        }
        return routingFee;
    }


    private Map<String, BigDecimal> getRoutingFee(String company, BigDecimal amount, Map<String, BigDecimal> fee, Integer organId, String receiver) {
        Map<String, BigDecimal> routingFee = new HashMap<>(2);
        routingFee.put("COM", BigDecimal.ZERO);
        routingFee.put("PER", BigDecimal.ZERO);
        if (company.equals("yaming")) {
            routingFee.put("PER", amount);
            return routingFee;
        }

        if (receiver != null) {
            routingFee.put(receiver, amount);
            return routingFee;
        }

        SysPaymentConfig paymentConfig = sysPaymentConfigService.findPaymentConfigByOrganId(organId);

        int payOrderNums = studentPaymentOrderService.findPayOrderNum(); //获取支付中和成功的订单数
        //前几笔收入私户
        Integer nums = Integer.parseInt(sysConfigDao.findConfigValue("per_account_nums"));
        if (paymentConfig != null && paymentConfig.getType().equals(1)) {
            nums = paymentConfig.getPerScale();
        }

        String type = null;
        int rem = (payOrderNums + 1) % 10;
        if (rem > 0 && rem <= nums) { //私人账户
            type = "PER";
        } else {
            type = "COM";
        }
        routingFee.put(type, amount);

        if (paymentConfig == null || !paymentConfig.getType().equals(2)) {
            return routingFee;
        }
        routingFee.put(type, BigDecimal.ZERO);
        for (Map.Entry<String, BigDecimal> feeEntry : fee.entrySet()) {
            if (feeEntry.getKey().equals("course")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getCourseFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getCourseFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("instrument")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getInstrumentFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getInstrumentFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("accessories")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getAccessoriesFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getAccessoriesFee(), RoutingFee);
            } else if (feeEntry.getKey().equals("other")) {
                BigDecimal RoutingFee = routingFee.get(paymentConfig.getOtherFee()).add(feeEntry.getValue());
                routingFee.put(paymentConfig.getOtherFee(), RoutingFee);
            }
        }
        return routingFee;
    }

}
