package com.zhongshu.card.server.core.service.pay;

import com.github.microservice.components.data.base.page.PageableModel;
import com.github.microservice.components.data.base.util.PageEntityUtil;
import com.github.microservice.core.util.JsonUtil;
import com.github.microservice.core.util.queue.ExecuteQueueUtil;
import com.github.microservice.pay.client.model.AccountModel;
import com.github.microservice.pay.client.model.PayProductParameter;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerQueryModel;
import com.github.microservice.pay.client.model.ledger.TransactionLogModel;
import com.github.microservice.pay.client.model.ledger.TransferTransactionsModel;
import com.github.microservice.pay.client.model.ledger.transaction.GeneralLedgerQueryTransactionLogModel;
import com.github.microservice.pay.client.model.ledger.transaction.TransactionLogAggregateRetModel;
import com.github.microservice.pay.client.product.senseless.chinaumsSenseless.conf.ChinaumsSenselessConf;
import com.github.microservice.pay.client.ret.ResultContent;
import com.github.microservice.pay.client.ret.ResultState;
import com.github.microservice.pay.client.service.PayProductAccountService;
import com.github.microservice.pay.client.service.ledger.GeneralLedgerService;
import com.github.microservice.pay.client.service.ledger.TransactionLogService;
import com.github.microservice.pay.client.service.product.SenselessPayService;
import com.github.microservice.pay.client.type.ledger.TransactionStatus;
import com.github.microservice.pay.client.type.ledger.TransactionType;
import com.github.microservice.types.payment.PaymentChannelType;
import com.github.microservice.types.payment.PaymentType;
import com.zhongshu.card.client.model.pay.*;
import com.zhongshu.card.client.model.paySetting.paySetting.OrgPayConfigModel;
import com.zhongshu.card.client.type.AuditStatus;
import com.zhongshu.card.client.type.ProcessStage;
import com.zhongshu.card.client.type.WithdrawStatus;
import com.zhongshu.card.client.type.paySetting.WithdrawMethodType;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.server.core.dao.pay.WithdrawOrderDao;
import com.zhongshu.card.server.core.domain.org.UserAccount;
import com.zhongshu.card.server.core.domain.pay.PayAccount;
import com.zhongshu.card.server.core.domain.pay.WithdrawOrder;
import com.zhongshu.card.server.core.domain.paySetting.ProjectMainPaySetting;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.service.org.OrganizationUserServiceImpl;
import com.zhongshu.card.server.core.service.org.UserOrgPermissService;
import com.zhongshu.card.server.core.service.paySetting.OrgPayAccountService;
import com.zhongshu.card.server.core.service.paySetting.ProjectMainPaySettingService;
import com.zhongshu.card.server.core.service.paySetting.ProjectPaySettingServiceImpl;
import com.zhongshu.card.server.core.service.user.UserAccountServiceImpl;
import com.zhongshu.card.server.core.util.BeanUtils;
import com.zhongshu.card.server.core.util.CommonUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Service
public class WithdrawService extends SuperService {

    @Autowired
    PayAccountService payAccountService;

    @Autowired
    TransactionLogService transactionLogService;

    @Autowired
    GeneralLedgerService generalLedgerService;

    @Autowired
    ProjectMainPaySettingService projectMainPaySettingService;

    @Autowired
    ProjectPaySettingServiceImpl projectPaySettingService;

    @Autowired
    UserAccountServiceImpl userAccountService;

    @Autowired
    WithdrawOrderDao withdrawOrderDao;

    @Autowired
    UserOrgPermissService userOrgPermissService;

    @Autowired
    SenselessPayService senselessPayService;

    @Autowired
    OrgPayAccountService orgPayAccountService;

    @Autowired
    PayProductAccountService payProductAccountService;

    @Autowired
    private OrganizationUserServiceImpl organizationUserService;

    /**
     * 查询当前在项目下所有的可提现的金额
     *
     * @param projectOid
     * @return
     */
    public ResultContent<Long> queryWithdrawAmount(String projectOid) {
        Long total = 0L;
        if (StringUtils.isEmpty(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        String userId = getCurrentUserId();
        // 查询用户加入的所有机构
        List<String> oids = organizationUserService.getUserOrgListOids(userId, projectOid);
        //TODO 可优化，通过group去查询账本，目前测试环境数据还没初始化group{projectoid}{oid}
        if (ObjectUtils.isNotEmpty(oids)) {
            for (String oid : oids) {
                PayAccount orgChildren = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.Settle);
                ResultContent<GeneralLedgerQueryModel> generalLedgerQueryModelResultContent = generalLedgerService.get(orgChildren.getLedgerId());
                if (generalLedgerQueryModelResultContent.getState().equals(ResultState.Success)) {
                    total = total + generalLedgerQueryModelResultContent.getContent().getBalance();
                }
            }
        }
        return ResultContent.buildContent(total);
    }

    /**
     * 查询可提现余额
     */
    public Object queryWithdrawAmount(String projectOid, String oid) {
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        if (StringUtils.isBlank(oid)) {
            oid = getCurrentOid();
        }
        PayAccount settleAccount = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.Settle);
        ResultContent<GeneralLedgerQueryModel> ledgerQueryModelResultContent = generalLedgerService.get(settleAccount.getLedgerId());
        if (!ledgerQueryModelResultContent.getState().equals(ResultState.Success)) {
            return com.github.microservice.net.ResultContent.buildFail("提现账本数据不存在");
        }
        return ResultContent.buildContent(ledgerQueryModelResultContent.getContent().getBalance());
    }

    /**
     * 查询当前支付渠道可提现余额
     */
    public com.github.microservice.net.ResultContent<Long> queryWithdrawAmount(String projectOid, String oid, PaymentType paymentType) {
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        if (StringUtils.isBlank(oid)) {
            oid = getCurrentOid();
        }
        return queryWithdrawAmountByPaymentType(projectOid, oid, paymentType);
//        if (null == amount){
//            return  com.github.microservice.net.ResultContent.buildFail("查询余额失败");
//        }
//        return com.github.microservice.net.ResultContent.buildContent(amount);
    }

    @SneakyThrows
    private com.github.microservice.net.ResultContent<Long> queryWithdrawAmountByPaymentType(String projectOid, String oid, PaymentType paymentType) {

        if (paymentType.equals(PaymentType.UnionFrictionlessPay)) {
            String orgAccount = orgPayAccountService.queryOgPayAccount(oid, paymentType);
            String projectAccount = orgPayAccountService.queryOgPayAccount(projectOid, paymentType);

            ResultContent<AccountModel> accountModelResultContent = payProductAccountService.get(orgAccount);

            if (!accountModelResultContent.getState().equals(ResultState.Success)) {
                return com.github.microservice.net.ResultContent.buildFail(accountModelResultContent.getMsg());
            }

            ChinaumsSenselessConf conf = (ChinaumsSenselessConf) accountModelResultContent.getContent().getConf();
            String withdrawMchId = conf.getWithdrawMchId();
            if (StringUtils.isEmpty(withdrawMchId)) {
                return com.github.microservice.net.ResultContent.buildFail("未配置提现商户号");
            }

            PayProductParameter<Object> parameter = new PayProductParameter<>();
            parameter.setAccountName(projectAccount);
            parameter.setMeta(Map.of("mchntNo", withdrawMchId));
            ResultContent<Object> resultContent = senselessPayService.withdrawAmountQuery(parameter);
            if (!resultContent.getState().equals(ResultState.Success)) {
                return com.github.microservice.net.ResultContent.buildFail(resultContent.getMsg());
            }
            String data = JsonUtil.toJson(resultContent.getContent());
            Map map = JsonUtil.toObject(data, Map.class);
            if (!map.get("respCode").equals("000000")) {
                return com.github.microservice.net.ResultContent.buildFail((String) map.get("respDesc"));
            }
            return com.github.microservice.net.ResultContent.buildContent(Long.parseLong((String) map.get("tzWithdrawAmt")));
        }

        PayAccount settleAccount = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.Settle);
        GeneralLedgerQueryTransactionLogModel queryTransactionLogModel = new GeneralLedgerQueryTransactionLogModel();
        queryTransactionLogModel.setFilter(Map.of("meta.paymentType", paymentType));
        queryTransactionLogModel.setGeneralLedgerId(new String[]{settleAccount.getLedgerId()});
        ResultContent<TransactionLogAggregateRetModel> aggregateRetModelResultContent = transactionLogService.aggregateAmount(queryTransactionLogModel);
        if (!aggregateRetModelResultContent.getState().equals(ResultState.Success)) {
            return com.github.microservice.net.ResultContent.buildFail(aggregateRetModelResultContent.getMsg());
        }
        long amount = aggregateRetModelResultContent.getContent().getStatistics().getCreditCount() + aggregateRetModelResultContent.getContent().getStatistics().getDebitCount();
        return com.github.microservice.net.ResultContent.buildContent(amount);
    }

    /**
     * 发起提现
     */
    public Object withdrawApply(WithdrawParam param) {
        String projectOid = param.getProjectOid();
        String oid = param.getOid();
        String userId = param.getUserId();
        PaymentType paymentType = param.getPaymentType();
        BigDecimal amount = param.getAmount();

        if(amount.compareTo(new BigDecimal(0)) == 0) {
            return com.github.microservice.net.ResultContent.buildFail("提现金额不能为0");
        }

        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        if (StringUtils.isBlank(oid)) {
            oid = getCurrentOid();
        }

        if (StringUtils.isBlank(userId)) {
            userId = getCurrentUserId();
        }

        List<UserAccount> userAccounts = userAccountService.getUserAccounts(List.of(userId));
        if (userAccounts == null || userAccounts.isEmpty()) {
            return com.github.microservice.net.ResultContent.buildFail("用户信息不存在");
        }

        //校验提现金额是否大约可以提现金额
        com.github.microservice.net.ResultContent<Long> resultContent = queryWithdrawAmountByPaymentType(projectOid, oid, paymentType);

        if (!resultContent.getState().equals(com.github.microservice.net.ResultState.Success)) {
            return com.github.microservice.net.ResultContent.buildFail(resultContent.getMsg());
        }
        Long waitAmount = resultContent.getContent();
        if (amount.compareTo(new BigDecimal(waitAmount)) > 0) {
            return com.github.microservice.net.ResultContent.buildFail("大于可提现金额");
        }
        //获取支付配置 为线上或者线下
        ProjectMainPaySetting projectMainPaySetting = projectMainPaySettingService.getProjectMainPaySetting(projectOid, paymentType);
        OrgPayConfigModel orgPayConfig = projectPaySettingService.getOrgPayConfig(projectOid, oid, paymentType);
        if (null == orgPayConfig || null == projectMainPaySetting) {
            return com.github.microservice.net.ResultContent.buildFail("支付产品未配置完成");
        }
        //支付中心划账：机构-已结算子账户- 机构-已冻结金额+
        PayAccount settleAccount = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.Settle);
        PayAccount frozenAccount = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.WithdrawFrozen);
        //构建转账参数
        TransferTransactionsModel transferModel = new TransferTransactionsModel();
        String withdrawOrderNo = CommonUtil.UUID();
        //构建出账账户
        TransferTransactionsModel.GeneralLedgerTransaction sourceTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        sourceTransaction.setGeneralLedgerId(settleAccount.getLedgerId());
        sourceTransaction.setOrderNumber(withdrawOrderNo);
        sourceTransaction.setTransactionType(TransactionType.WithdrawFrozen);
        sourceTransaction.setTransactionStatus(TransactionStatus.Success);
        sourceTransaction.setAmount(amount.negate().longValue());
        sourceTransaction.setMeta(Map.of("paymentType", paymentType, "paymentChannelType", paymentType.getChannelType(), "description", "提现冻结", "withdrawMethodType", projectMainPaySetting.getWithdrawMethodType()));
        transferModel.setSource(new TransferTransactionsModel.GeneralLedgerTransaction[]{sourceTransaction});
        //构建入账账户
        TransferTransactionsModel.GeneralLedgerTransaction destinationTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        destinationTransaction.setGeneralLedgerId(frozenAccount.getLedgerId());
        destinationTransaction.setOrderNumber(withdrawOrderNo);
        destinationTransaction.setTransactionType(TransactionType.WithdrawFrozen);
        destinationTransaction.setTransactionStatus(TransactionStatus.Success);
        destinationTransaction.setAmount(amount.longValue());
        destinationTransaction.setMeta(Map.of("paymentType", paymentType, "paymentChannelType", paymentType.getChannelType(), "description", "提现冻结", "withdrawMethodType", projectMainPaySetting.getWithdrawMethodType()));
        transferModel.setDestinations(new TransferTransactionsModel.GeneralLedgerTransaction[]{destinationTransaction});
        ResultContent<List<TransactionLogModel>> transfer = transactionLogService.transfer(transferModel);
        if (!transfer.getState().equals(ResultState.Success)) {
            return com.github.microservice.net.ResultContent.buildFail(transfer.getMsg());
        }
        //创建流程
        WithdrawOrder withdrawOrder = new WithdrawOrder();
        withdrawOrder.setWithdrawType(projectMainPaySetting.getWithdrawType());
        withdrawOrder.setWithdrawMethodType(projectMainPaySetting.getWithdrawMethodType());
        withdrawOrder.setBankAccountNumber(orgPayConfig.getBankSubName() + orgPayConfig.getBankName() + orgPayConfig.getBankAccountNumber());
        withdrawOrder.setOrderNo(withdrawOrderNo);
        withdrawOrder.setAmount(amount);
        withdrawOrder.setAuditStatus(AuditStatus.Wait);
        withdrawOrder.setSort(AuditStatus.Wait.getSort());
        withdrawOrder.setWithdrawUser(userAccounts.get(0).getName());
        withdrawOrder.setWithdrawUserId(userAccounts.get(0).getUserId());
        withdrawOrder.setFrozenTransactionLogs(transfer.getContent());
        withdrawOrder.setProjectOid(projectOid);
        withdrawOrder.setOid(oid);
        withdrawOrder.setPaymentType(paymentType);
        withdrawOrderDao.save(withdrawOrder);
        return com.github.microservice.net.ResultContent.buildSuccess();
    }

    /**
     * 审核
     */
    @SneakyThrows
    public com.github.microservice.net.ResultContent withdraw(ProcessWithdrawParam param) {
        String userId = param.getUserId();
        if (StringUtils.isBlank(userId)) {
            userId = getCurrentUserId();
        }

        List<UserAccount> userAccounts = userAccountService.getUserAccounts(List.of(userId));
        if (userAccounts == null || userAccounts.isEmpty()) {
            return com.github.microservice.net.ResultContent.buildFail("用户信息不存在");
        }
        //TODO 判断权限？

        //获取提现订单数据
        WithdrawOrder withdrawOrder = withdrawOrderDao.findTop1ById(param.getId());
        if (withdrawOrder == null) {
            return com.github.microservice.net.ResultContent.buildFail("数据不存在");
        }
        //判断状态是否为待审核
        if (!withdrawOrder.getAuditStatus().equals(AuditStatus.Wait)) {
            return com.github.microservice.net.ResultContent.buildFail("只能操作处理中的订单");
        }

        PayAccount withdrawFrozenAccount = payAccountService.getOrgChildren(withdrawOrder.getProjectOid(), withdrawOrder.getOid(), PaymentChannelType.WithdrawFrozen);
        PayAccount projectAccount = payAccountService.getProjectChildren(withdrawOrder.getProjectOid(), PaymentChannelType.SecretFreePayment);
        PayAccount settleAccount = payAccountService.getOrgChildren(withdrawOrder.getProjectOid(), withdrawOrder.getOid(), PaymentChannelType.Settle);

        withdrawOrder.setAttachInfo(param.getAttachInfo());
        withdrawOrder.setAttachFile(param.getAttachFile());

        //TODO 审批通过， 判断当前可提现余额是否大于提现订单金额
        if (param.getStatus().equals(AuditStatus.Success)) {//审批通过
            withdrawOrder.setAuditStatus(AuditStatus.Success);
            withdrawOrder.setSort(AuditStatus.Success.getSort());
            //判断是否线上提现，调用支付渠道对应的提现接口
            if (withdrawOrder.getWithdrawMethodType().equals(WithdrawMethodType.OnLine)) {
                return onlineWithdraw(withdrawOrder, userAccounts.get(0), settleAccount, withdrawFrozenAccount);
            } else {
                //划账，机构已冻结金额- 项目无感支付+
                TransferTransactionsModel transferTransactionsModel = buildTransferModel(projectAccount, withdrawFrozenAccount, withdrawOrder.getOrderNo(),
                        withdrawOrder.getAmount(), TransactionType.Withdrawal,
                        Map.of("paymentType", withdrawOrder.getPaymentType(), "paymentChannelType", withdrawOrder.getPaymentType().getChannelType(), "description", "提现"));
                ResultContent<List<TransactionLogModel>> transferResult = transactionLogService.transfer(transferTransactionsModel);
                if (!transferResult.getState().equals(ResultState.Success)) {
                    return com.github.microservice.net.ResultContent.buildFail(transferResult.getMsg());
                }
                withdrawOrder.setWithdrawTransactionLogs(transferResult.getContent());
            }
        } else if (param.getStatus().equals(AuditStatus.Fail)) { //审批拒绝
            withdrawOrder.setAuditStatus(AuditStatus.Fail);
            withdrawOrder.setSort(AuditStatus.Fail.getSort());
            //划账退回金额: 机构已冻结金额- 机构已结算 +
            TransferTransactionsModel transferTransactionsModel = buildTransferModel(settleAccount, withdrawFrozenAccount, withdrawOrder.getOrderNo(),
                    withdrawOrder.getAmount(), TransactionType.WithdrawRefund,
                    Map.of("paymentType", withdrawOrder.getPaymentType(), "paymentChannelType", withdrawOrder.getPaymentType().getChannelType(), "description", "提现退回"));
            ResultContent<List<TransactionLogModel>> transfer = transactionLogService.transfer(transferTransactionsModel);
            if (!transfer.getState().equals(ResultState.Success)) {
                return com.github.microservice.net.ResultContent.buildFail("余额退回失败");
            }
            withdrawOrder.setWithdrawTransactionLogs(transfer.getContent());
        }
        withdrawOrder.setAttachInfo(param.getAttachInfo());
        withdrawOrder.setAttachFile(param.getAttachFile());
        withdrawOrder.setProcessUser(userAccounts.get(0).getName());
        withdrawOrder.setWithdrawUserId(userAccounts.get(0).getUserId());
        withdrawOrder.setProcessTime(System.currentTimeMillis());
        withdrawOrderDao.save(withdrawOrder);
        return com.github.microservice.net.ResultContent.buildSuccess();
    }

    @SneakyThrows
    private com.github.microservice.net.ResultContent onlineWithdraw(WithdrawOrder withdrawOrder, UserAccount userAccount, PayAccount settleAccount, PayAccount withdrawFrozenAccount) {
        switch (withdrawOrder.getPaymentType()) {
            case UnionFrictionlessPay -> {
                String orgAccount = orgPayAccountService.queryOgPayAccount(withdrawOrder.getOid(), PaymentType.UnionFrictionlessPay);
                String projectPayAccount = orgPayAccountService.queryOgPayAccount(withdrawOrder.getProjectOid(), PaymentType.UnionFrictionlessPay);

                ResultContent<AccountModel> accountModelResultContent = payProductAccountService.get(orgAccount);

                if (!accountModelResultContent.getState().equals(ResultState.Success)) {
                    return com.github.microservice.net.ResultContent.buildFail(accountModelResultContent.getMsg());
                }

                ChinaumsSenselessConf conf = (ChinaumsSenselessConf) accountModelResultContent.getContent().getConf();
                String withdrawMchId = conf.getWithdrawMchId();
                if (StringUtils.isEmpty(withdrawMchId)) {
                    return com.github.microservice.net.ResultContent.buildFail("未配置提现商户号");
                }

                PayProductParameter<Object> parameter = new PayProductParameter<>();
                parameter.setAccountName(projectPayAccount);
                parameter.setMeta(Map.of("mchntNo", withdrawMchId, "orderNo", withdrawOrder.getOrderNo(), "amount", withdrawOrder.getAmount().toString()));
                ResultContent<Object> withdrawRet = senselessPayService.withdraw(parameter);
                withdrawOrder.setExpand(withdrawRet.getContent());

                Map bodyMap = JsonUtil.toObject(JsonUtil.toJson(withdrawRet.getContent()), Map.class);

                if (!bodyMap.get("respCode").equals("000000")) {//银联提现失败
                    withdrawOrder.setWithdrawStatusDesc("银行处理失败");
                    //划账退回金额: 机构已冻结金额- 机构已结算 +
                    TransferTransactionsModel transferTransactionsModel = buildTransferModel(settleAccount, withdrawFrozenAccount, withdrawOrder.getOrderNo(),
                            withdrawOrder.getAmount(), TransactionType.WithdrawRefund,
                            Map.of("paymentType", withdrawOrder.getPaymentType(), "paymentChannelType", withdrawOrder.getPaymentType().getChannelType(), "description", "提现退回"));
                    ResultContent<List<TransactionLogModel>> transfer = transactionLogService.transfer(transferTransactionsModel);
                    if (!transfer.getState().equals(ResultState.Success)) {
                        withdrawOrder.setWithdrawStatusDesc("银行处理失败，余额退回失败");
                        withdrawOrderDao.save(withdrawOrder);
                        return com.github.microservice.net.ResultContent.buildFail("银行处理失败，余额退回失败");
                    }
                    withdrawOrder.setWithdrawTransactionLogs(transfer.getContent());
                    withdrawOrder.setWithdrawStatus(WithdrawStatus.Fail);
                    withdrawOrderDao.save(withdrawOrder);
                    return com.github.microservice.net.ResultContent.buildFail((String) bodyMap.get("respDesc"));
                } else {
                    withdrawOrder.setWithdrawStatus(WithdrawStatus.Accepted);
                    withdrawOrder.setWithdrawStatusDesc("银行已受理");
                }
                withdrawOrder.setProcessUser(userAccount.getName());
                withdrawOrder.setProcessUserId(userAccount.getUserId());
                withdrawOrder.setProcessTime(System.currentTimeMillis());
                withdrawOrderDao.save(withdrawOrder);
                WithdrawStatus w = ExecuteQueueUtil.execute(1440, index -> {
                    return Map.of(1, 1000L, 2, 3000L, 3, 5000L, 4, 5000L, 5, 5000L).getOrDefault(index, 60 * 1000L);
                }, data -> {
                    var result = new ExecuteQueueUtil.Result<WithdrawStatus>();
                    com.github.microservice.net.ResultContent<WithdrawStatus> resultContent = withdrawQuery(withdrawOrder.getId());
                    if (!resultContent.getState().equals(com.github.microservice.net.ResultState.Success)) {
                        return null;
                    }
                    WithdrawStatus withdrawStatus = resultContent.getContent();
                    if (withdrawStatus.equals(WithdrawStatus.Success) || withdrawStatus.equals(WithdrawStatus.Fail)) {
                        result.setDone(true);
                        result.setData(withdrawStatus);
                        return result;
                    }
                    result.setData(withdrawStatus);
                    long time = System.currentTimeMillis() - data.getStartTime();
                    if (time > 3000L) {
                        result.setAsync(true);
                        return result;
                    }
                    return result;
                });
                return com.github.microservice.net.ResultContent.buildSuccess();
            }
        }
        return com.github.microservice.net.ResultContent.buildFail("该支付产品不支持线上提现方式");
    }

    private TransferTransactionsModel buildTransferModel(PayAccount credit, PayAccount debit, String orderNo, BigDecimal amount, TransactionType type, Map<String, Object> meta) {
        TransferTransactionsModel transferModel = new TransferTransactionsModel();
        //构建出账账户
        TransferTransactionsModel.GeneralLedgerTransaction sourceTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        sourceTransaction.setGeneralLedgerId(debit.getLedgerId());
        sourceTransaction.setOrderNumber(orderNo);
        sourceTransaction.setTransactionType(type);
        sourceTransaction.setTransactionStatus(TransactionStatus.Success);
        sourceTransaction.setAmount(amount.negate().longValue());
        sourceTransaction.setMeta(meta);
        transferModel.setSource(new TransferTransactionsModel.GeneralLedgerTransaction[]{sourceTransaction});
        //构建入账账户
        TransferTransactionsModel.GeneralLedgerTransaction destinationTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        destinationTransaction.setGeneralLedgerId(credit.getLedgerId());
        destinationTransaction.setOrderNumber(orderNo);
        destinationTransaction.setTransactionType(type);
        destinationTransaction.setTransactionStatus(TransactionStatus.Success);
        destinationTransaction.setAmount(amount.longValue());
        destinationTransaction.setMeta(meta);
        transferModel.setDestinations(new TransferTransactionsModel.GeneralLedgerTransaction[]{destinationTransaction});
        return transferModel;
    }

    /**
     * 查询机构提现记录
     */
    public com.github.microservice.net.ResultContent page(Pageable pageable, WithdrawPageParam param) {
        String userId = getCurrentUserId();
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        boolean isProjectManager = userOrgPermissService.userIsProjectManager(projectOid, userId);
        if (isProjectManager) {
            Page<WithdrawOrder> page = withdrawOrderDao.page(pageable, projectOid, null, param.getStartTime(), param.getEndTime(), param.getSearch(), param.getAuditStatus(), null);
            return com.github.microservice.net.ResultContent.buildContent(PageEntityUtil.concurrent2PageModel(page, this::toModel));
        }
        List<String> userManagerOids = userOrgPermissService.getUserManagerOids(projectOid, userId);

        if (userManagerOids == null || userManagerOids.isEmpty()) {
            return com.github.microservice.net.ResultContent.buildContent(PageEntityUtil.buildEmptyPage(pageable));
        }

        Page<WithdrawOrder> page = withdrawOrderDao.page(pageable, projectOid, userManagerOids.get(0), param.getStartTime(), param.getEndTime(), param.getSearch(), param.getAuditStatus(), null);
        return com.github.microservice.net.ResultContent.buildContent(PageEntityUtil.concurrent2PageModel(page, this::toModel));
    }

    public Object page(Pageable pageable, WithdrawMonthPageParam param){
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        String oid = param.getOid();
        if (StringUtils.isBlank(oid)) {
            oid = getCurrentOid();
        }

        if (param.getYear() == null || param.getMonth() == null) {
            return com.github.microservice.net.ResultContent.buildFail("year或month不能为null");
        }

        Long monthStartTime = DateUtils.getMonthStartTime(param.getYear(), param.getMonth());
        Long monthEndTime = DateUtils.getMonthEndTime(param.getYear(), param.getMonth());

        Page<WithdrawOrder> page = withdrawOrderDao.page(pageable, projectOid, oid, monthStartTime, monthEndTime, null, null, param.getWithdrawMethodType());
        return com.github.microservice.net.ResultContent.buildContent(PageEntityUtil.concurrent2PageModel(page, this::toModel));
    }

    /**
     * 查询提现余额明细
     * @return
     */
    public Object transactionLogPage(Pageable pageable, WithdrawMonthPageParam param){
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        String oid = param.getOid();
        if (StringUtils.isBlank(oid)) {
            oid = getCurrentOid();
        }

        if (param.getYear() == null || param.getMonth() == null) {
            return com.github.microservice.net.ResultContent.buildFail("year或month不能为null");
        }

        Long monthStartTime = DateUtils.getMonthStartTime(param.getYear(), param.getMonth());
        Long monthEndTime = DateUtils.getMonthEndTime(param.getYear(), param.getMonth());

        PayAccount orgChildren = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.Settle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{orgChildren.getLedgerId()});
        queryModel.setStartTime(monthStartTime);
        queryModel.setEndTime(monthEndTime);
        if (param.getWithdrawMethodType()!=null){
            queryModel.setFilter(Map.of("meta.withdrawMethodType", param.getWithdrawMethodType()));
        }
        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());
        pageableModel.setSort("createTime");
        queryModel.setPage(pageableModel);
        ResultContent<TransactionLogAggregateRetModel> aggregateResult = transactionLogService.aggregate(queryModel);
        if (!aggregateResult.getState().equals(ResultState.Success)){
            return com.github.microservice.net.ResultContent.buildFail(aggregateResult.getMsg());
        }
        return com.github.microservice.net.ResultContent.buildContent(aggregateResult.getContent().getPages());
    }

    private WithdrawOrderModel toModel(WithdrawOrder withdrawOrder) {
        WithdrawOrderModel model = new WithdrawOrderModel();
        if (withdrawOrder != null) {
            BeanUtils.copyProperties(withdrawOrder, model);
        }
        return model;
    }


    /**
     * 查询提现状态
     */
    @SneakyThrows
    public com.github.microservice.net.ResultContent<WithdrawStatus> withdrawQuery(String id) {
        //获取提现订单数据
        WithdrawOrder withdrawOrder = withdrawOrderDao.findTop1ById(id);
        if (withdrawOrder == null) {
            return com.github.microservice.net.ResultContent.buildFail("数据不存在");
        }

        if (!WithdrawStatus.Accepted.equals(withdrawOrder.getWithdrawStatus())) {
            return com.github.microservice.net.ResultContent.buildContent(withdrawOrder.getWithdrawStatus());
        }

        PayAccount withdrawFrozenAccount = payAccountService.getOrgChildren(withdrawOrder.getProjectOid(), withdrawOrder.getOid(), PaymentChannelType.WithdrawFrozen);
        PayAccount projectAccount = payAccountService.getProjectChildren(withdrawOrder.getProjectOid(), PaymentChannelType.SecretFreePayment);
        PayAccount settleAccount = payAccountService.getOrgChildren(withdrawOrder.getProjectOid(), withdrawOrder.getOid(), PaymentChannelType.Settle);


        switch (withdrawOrder.getPaymentType()) {
            case UnionFrictionlessPay -> {

                String orgAccount = orgPayAccountService.queryOgPayAccount(withdrawOrder.getOid(), PaymentType.UnionFrictionlessPay);
                String projectPayAccount = orgPayAccountService.queryOgPayAccount(withdrawOrder.getProjectOid(), PaymentType.UnionFrictionlessPay);

                ResultContent<AccountModel> accountModelResultContent = payProductAccountService.get(orgAccount);

                if (!accountModelResultContent.getState().equals(ResultState.Success)) {
                    return com.github.microservice.net.ResultContent.buildFail(accountModelResultContent.getMsg());
                }

                ChinaumsSenselessConf conf = (ChinaumsSenselessConf) accountModelResultContent.getContent().getConf();
                String withdrawMchId = conf.getWithdrawMchId();
                if (StringUtils.isEmpty(withdrawMchId)) {
                    return com.github.microservice.net.ResultContent.buildFail("未配置提现商户号");
                }

                PayProductParameter<Object> parameter = new PayProductParameter<>();
                parameter.setAccountName(projectPayAccount);

                parameter.setMeta(Map.of("mchntNo", withdrawMchId, "orderNo", withdrawOrder.getOrderNo(), "transDate", DateUtils.paresTime(withdrawOrder.getCreateTime(), DateUtils.patternyyyyMMDD)));

                ResultContent<Object> resultContent = senselessPayService.withdrawQuery(parameter);
                if (!resultContent.getState().equals(ResultState.Success)) {
                    return com.github.microservice.net.ResultContent.buildFail("银联请求失败");
                }
                String json = JsonUtil.toJson(resultContent.getContent());
                Map map = JsonUtil.toObject(json, Map.class);

                if (!map.get("respCode").equals("000000")) {//查询成功
                    return com.github.microservice.net.ResultContent.buildFail("银联请求错误");
                }
                String status = (String) map.get("status");
                if (status.equals("-1") || status.equals("0") || status.equals("1") || status.equals("2") || status.equals("6")) {
                    return com.github.microservice.net.ResultContent.buildContent(WithdrawStatus.Accepted);
                }

                if (status.equals("3")) {
                    boolean update = withdrawOrderDao.updateWithdrawStatus(withdrawOrder.getId(), WithdrawStatus.Success, (String) map.get("desc"));
                    if (!update) {
                        return com.github.microservice.net.ResultContent.buildFail("系统繁忙请重试");
                    }
                    //TODO 处理账单
                    //划账，机构已冻结金额- 项目无感支付+
                    TransferTransactionsModel transferTransactionsModel = buildTransferModel(projectAccount, withdrawFrozenAccount, withdrawOrder.getOrderNo(),
                            withdrawOrder.getAmount(), TransactionType.Withdrawal,
                            Map.of("paymentType", withdrawOrder.getPaymentType(), "paymentChannelType", withdrawOrder.getPaymentType().getChannelType(), "description", "提现"));
                    ResultContent<List<TransactionLogModel>> transferResult = transactionLogService.transfer(transferTransactionsModel);
                    if (!transferResult.getState().equals(ResultState.Success)) {
                        return com.github.microservice.net.ResultContent.buildFail(transferResult.getMsg());
                    }
                    withdrawOrder.setWithdrawTransactionLogs(transferResult.getContent());
                    withdrawOrderDao.save(withdrawOrder);
                    return com.github.microservice.net.ResultContent.buildContent(WithdrawStatus.Success);
                }

                if (status.equals("4")) {
                    boolean update = withdrawOrderDao.updateWithdrawStatus(withdrawOrder.getId(), WithdrawStatus.Fail, (String) map.get("desc"));
                    if (!update) {
                        return com.github.microservice.net.ResultContent.buildFail("系统繁忙请重试");
                    }
                    //TODO 处理账单
                    TransferTransactionsModel transferTransactionsModel = buildTransferModel(settleAccount, withdrawFrozenAccount, withdrawOrder.getOrderNo(),
                            withdrawOrder.getAmount(), TransactionType.WithdrawRefund,
                            Map.of("paymentType", withdrawOrder.getPaymentType(), "paymentChannelType", withdrawOrder.getPaymentType().getChannelType(), "description", "提现退回"));
                    ResultContent<List<TransactionLogModel>> transfer = transactionLogService.transfer(transferTransactionsModel);
                    if (!transfer.getState().equals(ResultState.Success)) {
                        return com.github.microservice.net.ResultContent.buildFail("余额退回失败");
                    }
                    withdrawOrder.setWithdrawTransactionLogs(transfer.getContent());
                    withdrawOrderDao.save(withdrawOrder);
                    return com.github.microservice.net.ResultContent.buildContent(WithdrawStatus.Fail);
                }
            }
        }
        return com.github.microservice.net.ResultContent.buildContent(withdrawOrder.getWithdrawStatus());
    }

    /**
     * 查询详情
     */
    public Object queryDetailById(String id) {
        WithdrawOrder withdrawOrder = withdrawOrderDao.findTop1ById(id);
        WithdrawOrderModel model = toModel(withdrawOrder);

        ProcessStage[] values = ProcessStage.values();
        List<WithdrawProcessModel> list = Arrays.stream(values).map(it -> {
            WithdrawProcessModel withdrawProcessModel = new WithdrawProcessModel();
            withdrawProcessModel.setProcessStage(it);
            withdrawProcessModel.setShow(false);
            if (it.equals(ProcessStage.Apply)) {
                withdrawProcessModel.setStatus(ProcessStage.Apply.name());
                withdrawProcessModel.setTime(withdrawOrder.getCreateTime());
                withdrawProcessModel.setUser(withdrawOrder.getWithdrawUser());
                withdrawProcessModel.setSort(0);
                withdrawProcessModel.setShow(true);
            }
            if (it.equals(ProcessStage.Audit)) {
                withdrawProcessModel.setSort(1);
                if (!withdrawOrder.getAuditStatus().equals(AuditStatus.Wait)) {
                    withdrawProcessModel.setStatus(withdrawOrder.getAuditStatus().name());
                    withdrawProcessModel.setTime(withdrawOrder.getProcessTime());
                    withdrawProcessModel.setUser(withdrawOrder.getProcessUser());
                    withdrawProcessModel.setShow(true);
                }
            }

            if (it.equals(ProcessStage.Transfer)) {
                withdrawProcessModel.setSort(2);
                if (withdrawOrder.getAuditStatus().equals(AuditStatus.Success)) {
                    withdrawProcessModel.setStatus(withdrawOrder.getWithdrawStatus().name());
                    withdrawProcessModel.setTime(withdrawOrder.getUpdateTime());
                    withdrawProcessModel.setShow(true);
                }
            }
            return withdrawProcessModel;
        }).toList();

        model.setWithdrawProcessModel(list);
        return model;
    }

    public Object queryDetailByOrderNo(String orderNo) {
        return null;
    }

    /**
     * 处理银联无感支付，提现结果通知回调
     */
    public Object handleWithdrawMessage() {
        return null;
    }
}
