package com.mmc.iuav.user.service.wallet.impl;

import com.mmc.iuav.general.CodeUtil;
import com.mmc.iuav.page.PageResult;
import com.mmc.iuav.response.ResultBody;
import com.mmc.iuav.user.dao.UserServiceDao;
import com.mmc.iuav.user.dao.wallet.PayWalletDao;
import com.mmc.iuav.user.entity.UserAccountDO;
import com.mmc.iuav.user.entity.XzWithdrawalApplyDO;
import com.mmc.iuav.user.entity.wallet.PayLogDO;
import com.mmc.iuav.user.entity.wallet.PayWalletDO;
import com.mmc.iuav.user.entity.wallet.UserBillingDetailVO;
import com.mmc.iuav.user.entity.wallet.WithdrawalLogDO;
import com.mmc.iuav.user.enums.PayMethodEnums;
import com.mmc.iuav.user.model.dto.wallet.PayWalletDTO;
import com.mmc.iuav.user.model.qo.wallet.WalletFlowQO;
import com.mmc.iuav.user.model.vo.WithdrawalInfoVO;
import com.mmc.iuav.user.model.vo.wallet.*;
import com.mmc.iuav.user.service.wallet.PayWalletService;
import com.mmc.iuav.user.util.TDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author LW
 * @date 2023/8/18 11:36
 * 概要：
 */
@Service
@Slf4j
public class PayWalletServiceImpl implements PayWalletService {
    @Resource
    PayWalletDao payWalletDao;
    @Resource
    UserServiceDao userServiceDao;

    @Override
    public ResultBody getPayWalletInfo(Integer userAccountId) {
        PayWalletDO wallet = payWalletDao.getPayWalletByUser(userAccountId);
        if (wallet == null) {
            return null;
        }
        PayWalletDTO pd = wallet.buildPayWalletDTO();
        pd.mathTotal();
        return ResultBody.success(pd);
    }

    @Override
    public ResultBody initPayWallet(Integer userAccountId) {
        PayWalletDO wallet = new PayWalletDO();
        wallet.defaultValue();
        wallet.setUserAccountId(userAccountId);
        payWalletDao.insertPayWalletInfo(wallet);
        return ResultBody.success();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBody feignWalletFlow(WalletFlowVO walletFlowVO) {
        // 获取发布者的信息
        PublisherWalletFlowVO publisherWalletFlowVO = walletFlowVO.getPublisherWalletFlowVO();
        // 获取接单者的信息
        FlyerWalletFlowVO flyerWalletFlowVO = walletFlowVO.getFlyerWalletFlowVO();
        // 发布者的钱包信息
        PayWalletDO publishWallet = new PayWalletDO();
        // 接单者的钱包信息
        PayWalletDO flyerWallet = new PayWalletDO();
        // 获取用户钱包信息
        if (publisherWalletFlowVO != null) {
            publishWallet = payWalletDao.getPayWalletByUser(publisherWalletFlowVO.getUserAccountId());
        }
        if (flyerWalletFlowVO != null) {
            flyerWallet = payWalletDao.getPayWalletByUser(flyerWalletFlowVO.getUserAccountId());
        }
        // 判断状态进行资金的扣减等于100时 发布订单
        if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.PUBLISH_ORDER.getCode())) {
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getCashAmount())
                    .add(publisherWalletFlowVO.getTopYxjAmount()).add(publisherWalletFlowVO.getUrgentYxjAmount()));
            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().subtract(publisherWalletFlowVO.getCashAmount())
                    .subtract(publisherWalletFlowVO.getTopYxjAmount()).subtract(publisherWalletFlowVO.getUrgentYxjAmount()));
            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getSalaryAmount())
                    .add(publisherWalletFlowVO.getTopSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().subtract(publisherWalletFlowVO.getSalaryAmount())
                    .subtract(publisherWalletFlowVO.getTopSalaryAmount()).subtract(publisherWalletFlowVO.getUrgentSalaryAmount()));
            int i = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if (i > 0) {
                PayLogDO payLogDO = buildPayLogDO(publisherWalletFlowVO, null);
                payLogDO.setCashAmtPaid(publisherWalletFlowVO.getCashAmount().add(publisherWalletFlowVO.getTopYxjAmount()).add(publisherWalletFlowVO.getUrgentYxjAmount()));
                payLogDO.setSalaryAmtPaid(publisherWalletFlowVO.getSalaryAmount().add(publisherWalletFlowVO.getTopSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount()));
                // 插入流水记录表
                payWalletDao.insertPayLogDO(payLogDO);
                return ResultBody.success();
            } else {
                log.error("发布订单时，用户钱包更新失败，用户id是:{}，传入参数是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
                return ResultBody.error("钱包操作错误");
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.CANCEL_ORDER_TAKING.getCode())) {
            // 等于200时 发布方取消订单，无飞手接单
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getCashAmount()));
            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().add(publisherWalletFlowVO.getTopYxjAmount())
                    .add(publisherWalletFlowVO.getUrgentYxjAmount()).subtract(publisherWalletFlowVO.getCashAmount()));
            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getSalaryAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().add(publisherWalletFlowVO.getTopSalaryAmount())
                    .add(publisherWalletFlowVO.getUrgentSalaryAmount()).subtract(publisherWalletFlowVO.getSalaryAmount()));
            int i = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if ((i > 0) && (publisherWalletFlowVO.getCashAmount().compareTo(BigDecimal.ZERO) > 0 || publisherWalletFlowVO.getSalaryAmount().compareTo(BigDecimal.ZERO) > 0)) {
                PayLogDO payLogDO = buildPayLogDO(publisherWalletFlowVO, null);
                // 插入流水记录表
                payWalletDao.insertPayLogDO(payLogDO);
                return ResultBody.success();
            } else {
                log.error("发布方取消订单，无飞手接单时，用户id是:{}，传入参数是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
                return ResultBody.error("钱包操作错误");
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.RECEIVED_ORDER_CANCEL.getCode())) {
            // 等于300时 发布方取消订单，有飞手接单
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getCashAmount()));
            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().subtract(publisherWalletFlowVO.getCashAmount())
                    .add(publisherWalletFlowVO.getYxjCashPledge()).add(publisherWalletFlowVO.getTopYxjAmount()).add(publisherWalletFlowVO.getUrgentYxjAmount()));
            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getSalaryAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().add(publisherWalletFlowVO.getSalaryCashPledge())
                    .subtract(publisherWalletFlowVO.getSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount().add(publisherWalletFlowVO.getTopSalaryAmount())));
            // 更新发布者钱包数据
            int publishUpdateCount = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if (publishUpdateCount <= 0) {
                log.error("发布方取消订单，有飞手接单时，发单方用户钱包更新失败，更新参数是：{},发单方用户id是:{}，传入参数是：{}", publishUpdatePayWallet, publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
                return ResultBody.error("钱包操作错误");
            }
            if (publisherWalletFlowVO.getCashAmount().compareTo(BigDecimal.ZERO) > 0 || publisherWalletFlowVO.getSalaryAmount().compareTo(BigDecimal.ZERO) > 0) {
                // 插入发布者流水记录表
                sendBackPublishPayLog(publisherWalletFlowVO, 1);
            }
            // 飞手钱包更新信息
            PayWalletDO flyerUpdatePayWallet = new PayWalletDO();
            // 断言此处必定不为空
            assert flyerWalletFlowVO != null;
            flyerUpdatePayWallet.setUserAccountId(flyerWalletFlowVO.getUserAccountId());
            flyerUpdatePayWallet.setPid(flyerWallet.getPid());
            flyerUpdatePayWallet.setCashAmt(flyerWallet.getCashAmt().add(flyerWalletFlowVO.getCashAmount()));
            flyerUpdatePayWallet.setCashFreeze(flyerWallet.getCashFreeze().subtract(flyerWalletFlowVO.getCashAmount()));
            flyerUpdatePayWallet.setSalaryAmt(flyerWallet.getSalaryAmt().add(flyerWalletFlowVO.getSalaryAmount()).subtract(publisherWalletFlowVO.getPercentagePenaltyOfOrder()));
            flyerUpdatePayWallet.setSalaryFreeze(flyerWallet.getSalaryFreeze().subtract(flyerWalletFlowVO.getSalaryAmount()));
            int flyerUpdateCount = payWalletDao.updatePayWallet(flyerUpdatePayWallet);
            if (flyerUpdateCount > 0) {
                // 记录订单保证金退回记录
                if (flyerWalletFlowVO.getCashAmount().compareTo(BigDecimal.ZERO) > 0 || flyerWalletFlowVO.getSalaryAmount().compareTo(BigDecimal.ZERO) > 0) {
                    sendBackPledge(flyerWalletFlowVO);
                }
                // 获得违约金流水记录
                paymentOfLiquidatedDamage(publisherWalletFlowVO, flyerWalletFlowVO, 0);
                return ResultBody.success();
            } else {
                log.error("发布方取消订单，有飞手接单时，飞手用户钱包更新失败,飞手用户id是:{}，接单方传入参数是：{}，发单方违约金是：{}", flyerWalletFlowVO.getUserAccountId(), flyerWalletFlowVO, publisherWalletFlowVO.getPercentagePenaltyOfOrder());
            }
        } else if (flyerWalletFlowVO != null && flyerWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.FLYING_ORDER_TAKING.getCode())) {
            // 状态为400时 表示飞手接单
            // 飞手钱包更新信息
            int flyerUpdateCount = buildFlyerWallet(flyerWalletFlowVO, flyerWallet);
            if (flyerUpdateCount > 0) {
                PayLogDO flyerPayLogDO = buildPayLogDO(null, flyerWalletFlowVO);
                // 插入流水记录表
                payWalletDao.insertPayLogDO(flyerPayLogDO);
                return ResultBody.success();
            } else {
                log.error("飞手抢单时，飞手用户钱包更新失败,飞手用户id是:{}，传入参数是：{}", flyerWalletFlowVO.getUserAccountId(), flyerWalletFlowVO);
            }
        } else if (flyerWalletFlowVO != null && flyerWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.CUSTOMER_SERVICE_CANCEL_ORDER.getCode())) {
            // 状态为500时 客服判定飞手无责取消订单
            // 飞手钱包更新信息
            int flyerUpdateCount = buildFlyerWallet(flyerWalletFlowVO, flyerWallet);
            if (flyerUpdateCount > 0) {
                PayLogDO flyerPayLogDO = buildPayLogDO(null, flyerWalletFlowVO);
                // 插入流水记录表
                payWalletDao.insertPayLogDO(flyerPayLogDO);
                return ResultBody.success();
            } else {
                log.error("客服判定飞手无责取消订单时，飞手用户钱包更新失败,飞手用户id是:{}，传入参数是：{}", flyerWalletFlowVO.getUserAccountId(), flyerWalletFlowVO);
            }
        } else if (flyerWalletFlowVO != null && flyerWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.FLYER_CANCEL_ORDER.getCode())) {
            // 状态为600时 飞手有责取消订单
            // 飞手钱包更新信息
            PayWalletDO flyerUpdatePayWallet = new PayWalletDO();
            flyerUpdatePayWallet.setUserAccountId(flyerWalletFlowVO.getUserAccountId());
            flyerUpdatePayWallet.setPid(flyerWallet.getPid());
            flyerUpdatePayWallet.setCashFreeze(flyerWallet.getCashFreeze().add(flyerWalletFlowVO.getYxjCashPledge()));
            flyerUpdatePayWallet.setSalaryFreeze(flyerWallet.getSalaryFreeze().add(flyerWalletFlowVO.getSalaryCashPledge()));
            int flyerUpdateCount = payWalletDao.updatePayWallet(flyerUpdatePayWallet);
            if (flyerUpdateCount <= 0) {
                log.error("飞手有责取消订单，飞手用户钱包更新失败,飞手用户id是:{}，接单方传入参数是：{}", flyerWalletFlowVO.getUserAccountId(), flyerWalletFlowVO);
                return ResultBody.error("钱包操作错误");
            }
            // 发单者钱包更新信息
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            // 断言此处必定不为空
            assert publisherWalletFlowVO != null;
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getCashAmount())
                    .add(publisherWalletFlowVO.getTopYxjAmount()).add(publisherWalletFlowVO.getTopYxjAmount()));

            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getSalaryAmount())
                    .subtract(flyerWalletFlowVO.getPercentagePenaltyOfOrder()));

            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().subtract(publisherWalletFlowVO.getCashAmount())
                    .subtract(publisherWalletFlowVO.getUrgentYxjAmount()).subtract(publisherWalletFlowVO.getTopYxjAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().subtract(publisherWalletFlowVO.getSalaryAmount())
                    .subtract(publisherWalletFlowVO.getUrgentSalaryAmount()).subtract(publisherWalletFlowVO.getTopSalaryAmount()));
            int publishUpdateCount = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if (publishUpdateCount > 0) {
                // 记录飞手违约金流水
                paymentOfLiquidatedDamage(publisherWalletFlowVO, flyerWalletFlowVO, 1);
                if (publisherWalletFlowVO.getCashAmount().compareTo(BigDecimal.ZERO) > 0
                        || publisherWalletFlowVO.getUrgentYxjAmount().compareTo(BigDecimal.ZERO) > 0
                        || publisherWalletFlowVO.getTopYxjAmount().compareTo(BigDecimal.ZERO) > 0
                        || publisherWalletFlowVO.getSalaryAmount().compareTo(BigDecimal.ZERO) > 0
                        || publisherWalletFlowVO.getUrgentSalaryAmount().compareTo(BigDecimal.ZERO) > 0
                        || publisherWalletFlowVO.getTopSalaryAmount().compareTo(BigDecimal.ZERO) > 0) {
                    // 记录退回订单金额
                    sendBackPublishPayLog(publisherWalletFlowVO, 0);
                }
                return ResultBody.success();
            } else {
                log.error("飞手有责取消订单,发布者用户钱包更新失败,发布者用户id是:{}，发布方传入参数是：{}，接单方方违约金是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO, flyerWalletFlowVO.getPercentagePenaltyOfOrder());
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.NORMAL_SETTLEMENT.getCode())) {
            // 状态为700时 正常订单结算
            // 解冻发布方订单的钱包金额
            PayWalletDO publishPayWalletDO = new PayWalletDO();
            publishPayWalletDO.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishPayWalletDO.setPid(publishWallet.getPid());
            publishPayWalletDO.setCashFreeze(publishWallet.getCashFreeze().add(publisherWalletFlowVO.getCashAmount())
                    .add(publisherWalletFlowVO.getUrgentYxjAmount()).add(publisherWalletFlowVO.getTopYxjAmount()));
            publishPayWalletDO.setSalaryFreeze(publishWallet.getSalaryFreeze().add(publisherWalletFlowVO.getSalaryAmount())
                    .add(publisherWalletFlowVO.getTopSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount()));
            int publishUpdateCount = payWalletDao.updatePayWallet(publishPayWalletDO);
            if (publishUpdateCount <= 0) {
                log.error("正常结算时，发布者用户钱包更新失败，发布者id是：{}，发布者传参是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
            // 增加接单方钱包金额
            assert flyerWalletFlowVO != null;
            int flyerUpdateCount = addFlyerSalary(publisherWalletFlowVO, flyerWalletFlowVO, flyerWallet);
            if (flyerUpdateCount > 0) {
                // 记录订单保证金退回记录
                sendBackPledge(flyerWalletFlowVO);
                // 记录订单结算流水记录
                PayLogDO flyerPayLogDO = buildFlyerLog(publisherWalletFlowVO, flyerWalletFlowVO.getUserAccountId());
                // 插入接单者流水记录表
                payWalletDao.insertPayLogDO(flyerPayLogDO);
                return ResultBody.success();
            } else {
                log.error("正常结算时，接单方用户钱包更新失败，接单者id是：{}，发布者传参是：{}", flyerWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.MODIFY_THE_ORDER.getCode())) {
            // 状态为800时 发布方修改金额大于原来订单佣金
            // 发布方还需补金额
            if (releaseOrCancelOrderWallet(publisherWalletFlowVO, publishWallet)) {
                PayLogDO payLogDO = buildPayLogDO(publisherWalletFlowVO, null);
                // 插入流水记录表
                payWalletDao.insertPayLogDO(payLogDO);
                return ResultBody.success();
            } else {
                log.error("发布方修改金额大于原来订单佣金时，用户钱包更新失败，用户id是:{}，传入参数是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
                return ResultBody.error("钱包操作错误");
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.FLYING_HAND_NOT_CONFIRMED_GT.getCode())) {
            // 状态为900时 飞手未确认修改金额大于原订单状态时订单结算
            // 退回发布方后面补的金额
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getRefundSalaryAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().subtract(publisherWalletFlowVO.getRefundSalaryAmount()));
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getRefundCashAmount()));
            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().subtract(publisherWalletFlowVO.getRefundCashAmount()));
            int publishUpdateCount = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if (publishUpdateCount <= 0) {
                log.error("飞手未确认修改金额大于原订单状态时，发布者用户钱包更新失败，发布者id是：{}，发布者参数是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
            // 记录发单方退回多余金额记录
            refund(publisherWalletFlowVO);
            // 增加接单方钱包金额
            assert flyerWalletFlowVO != null;
            int flyerUpdateCount = addFlyerSalary(publisherWalletFlowVO, flyerWalletFlowVO, flyerWallet);
            if (flyerUpdateCount > 0) {
                // 记录订单保证金退回记录
                sendBackPledge(flyerWalletFlowVO);
                // 记录订单结算流水记录
                PayLogDO flyerPayLogDO = buildFlyerLog(publisherWalletFlowVO, flyerWalletFlowVO.getUserAccountId());
                // 插入接单者流水记录表
                payWalletDao.insertPayLogDO(flyerPayLogDO);
                return ResultBody.success();
            } else {
                log.error("飞手未确认修改金额大于原订单状态时，接单方用户钱包更新失败，接单者id是：{}，发布者传参是：{}", flyerWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
        } else if (publisherWalletFlowVO != null && publisherWalletFlowVO.getModeOfPayment().equals(PayMethodEnums.FLYING_HAND_CONFIRM_LT.getCode())) {
            // 状态为1000时 飞手确认修改金额小于原订单状态
            // 退回发布方多余原订单金额,解冻钱包金额
            PayWalletDO publishUpdatePayWallet = new PayWalletDO();
            publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            publishUpdatePayWallet.setPid(publishWallet.getPid());
            publishUpdatePayWallet.setCashAmt(publishWallet.getCashAmt().add(publisherWalletFlowVO.getRefundCashAmount()));
            publishUpdatePayWallet.setCashFreeze(publishWallet.getCashFreeze().subtract(publisherWalletFlowVO.getRefundCashAmount())
                    .subtract(publisherWalletFlowVO.getCashAmount()).add(publisherWalletFlowVO.getUrgentYxjAmount()).add(publisherWalletFlowVO.getTopYxjAmount()));
            publishUpdatePayWallet.setSalaryAmt(publishWallet.getSalaryAmt().add(publisherWalletFlowVO.getRefundSalaryAmount()));
            publishUpdatePayWallet.setSalaryFreeze(publishWallet.getSalaryFreeze().subtract(publisherWalletFlowVO.getRefundSalaryAmount())
                    .subtract(publisherWalletFlowVO.getSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount()).add(publisherWalletFlowVO.getTopYxjAmount()));
            int publishUpdateCount = payWalletDao.updatePayWallet(publishUpdatePayWallet);
            if (publishUpdateCount <= 0) {
                log.error("飞手确认修改金额小于原订单状态，发布者用户钱包更新失败，发布者id是：{}，发布者参数是：{}", publisherWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
            // 记录多余退款记录
            refund(publisherWalletFlowVO);
            // 增加接单方钱包金额
            assert flyerWalletFlowVO != null;
            int flyerUpdateCount = addFlyerSalary(publisherWalletFlowVO, flyerWalletFlowVO, flyerWallet);
            if (flyerUpdateCount > 0) {
                // 记录订单保证金退回记录
                sendBackPledge(flyerWalletFlowVO);
                // 记录订单结算流水记录
                PayLogDO flyerPayLogDO = buildFlyerLog(publisherWalletFlowVO, flyerWalletFlowVO.getUserAccountId());
                // 插入接单者流水记录表
                payWalletDao.insertPayLogDO(flyerPayLogDO);
                return ResultBody.success();
            } else {
                log.error("飞手确认修改金额小于原订单状态，接单方用户钱包更新失败，接单者id是：{}，发布者传参是：{}", flyerWalletFlowVO.getUserAccountId(), publisherWalletFlowVO);
            }
        }
        return ResultBody.error("钱包操作错误");
    }

    /**
     * @param publisherWalletFlowVO
     * @param flag                  0 未违约取消 1 违约取消
     */
    private void sendBackPublishPayLog(PublisherWalletFlowVO publisherWalletFlowVO, Integer flag) {
        PayLogDO payLogDO = new PayLogDO();
        String payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + publisherWalletFlowVO.getUserAccountId() + CodeUtil.getRandomNum(4);
        if (flag == 0) {
            payLogDO.setPayMethod(200);
            payLogDO.setCashAmtPaid(publisherWalletFlowVO.getCashAmount().add(publisherWalletFlowVO.getTopYxjAmount()).add(publisherWalletFlowVO.getUrgentYxjAmount()));
            payLogDO.setSalaryAmtPaid(publisherWalletFlowVO.getSalaryAmount().add(publisherWalletFlowVO.getTopSalaryAmount()).add(publisherWalletFlowVO.getUrgentSalaryAmount()));
        } else {
            payLogDO.setPayMethod(300);
            payLogDO.setCashAmtPaid(publisherWalletFlowVO.getCashAmount());
            payLogDO.setSalaryAmtPaid(publisherWalletFlowVO.getSalaryAmount());
        }
        payLogDO.setPayNo(payNo);
        payLogDO.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
        payLogDO.setOperateUser(publisherWalletFlowVO.getUserAccountId());
        // 插入流水记录表
        payWalletDao.insertPayLogDO(payLogDO);
    }

    /**
     * @param publisherWalletFlowVO 发布者信息
     * @param flyerWalletFlowVO     接单者信息
     * @param flag                  0：发布者违约 1：抢单者违约
     */
    private void paymentOfLiquidatedDamage(PublisherWalletFlowVO publisherWalletFlowVO, FlyerWalletFlowVO flyerWalletFlowVO, Integer flag) {
        PayLogDO flyerPayLogDO = new PayLogDO();
        String payNo;
        Integer userAccountId;
        BigDecimal percentagePenaltyOfOrder;
        if (flag == 0) {
            // 生成支付流水号(规则"T" + 时间戳 + 用户id + 随机数4位)
            payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + flyerWalletFlowVO.getUserAccountId() + CodeUtil.getRandomNum(4);
            userAccountId = flyerWalletFlowVO.getUserAccountId();
            percentagePenaltyOfOrder = publisherWalletFlowVO.getPercentagePenaltyOfOrder();
            flyerPayLogDO.setOperateUser(userAccountId);
        } else {
            // 生成支付流水号(规则"T" + 时间戳 + 用户id + 随机数4位)
            payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + publisherWalletFlowVO.getUserAccountId() + CodeUtil.getRandomNum(4);
            userAccountId = publisherWalletFlowVO.getUserAccountId();
            flyerPayLogDO.setOperateUser(userAccountId);
            percentagePenaltyOfOrder = flyerWalletFlowVO.getPercentagePenaltyOfOrder();
        }
        flyerPayLogDO.setPayMethod(1300);
        flyerPayLogDO.setPayNo(payNo);
        flyerPayLogDO.setUserAccountId(userAccountId);
        flyerPayLogDO.setCashAmtPaid(BigDecimal.ZERO);
        flyerPayLogDO.setSalaryAmtPaid(percentagePenaltyOfOrder.abs());
        // 插入流水记录表
        payWalletDao.insertPayLogDO(flyerPayLogDO);
    }

    private PayLogDO buildFlyerLog(PublisherWalletFlowVO publisherWalletFlowVO, Integer userAccountId) {
        PayLogDO payLogWalletDO = new PayLogDO();
        // 生成支付流水号(规则"T" + 时间戳 + 用户id + 随机数4位)
        String flyerPayNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + userAccountId + CodeUtil.getRandomNum(4);
        payLogWalletDO.setPayMethod(publisherWalletFlowVO.getModeOfPayment());
        payLogWalletDO.setPayNo(flyerPayNo);
        payLogWalletDO.setUserAccountId(userAccountId);
        payLogWalletDO.setSalaryAmtPaid(publisherWalletFlowVO.getFlyerSalaryAmount());
        payLogWalletDO.setOperateUser(publisherWalletFlowVO.getUserAccountId());
        return payLogWalletDO;
    }

    private void sendBackPledge(FlyerWalletFlowVO flyerWalletFlowVO) {
        if (flyerWalletFlowVO.getCashAmount().compareTo(new BigDecimal(0)) > 0 || flyerWalletFlowVO.getSalaryAmount().compareTo(new BigDecimal(0)) > 0) {
            PayLogDO flyerPledgeSendBack = buildPayLogDO(null, flyerWalletFlowVO);
            flyerPledgeSendBack.setPayMethod(500);
            // 插入接单者流水记录表
            payWalletDao.insertPayLogDO(flyerPledgeSendBack);
        }
    }

    private int buildFlyerWallet(FlyerWalletFlowVO flyerWalletFlowVO, PayWalletDO flyerWallet) {
        PayWalletDO flyerUpdatePayWallet = new PayWalletDO();
        flyerUpdatePayWallet.setUserAccountId(flyerWalletFlowVO.getUserAccountId());
        flyerUpdatePayWallet.setPid(flyerWallet.getPid());
        flyerUpdatePayWallet.setCashAmt(flyerWallet.getCashAmt().add(flyerWalletFlowVO.getCashAmount()));
        flyerUpdatePayWallet.setCashFreeze(flyerWallet.getCashFreeze().subtract(flyerWalletFlowVO.getCashAmount()));
        flyerUpdatePayWallet.setSalaryAmt(flyerWallet.getSalaryAmt().add(flyerWalletFlowVO.getSalaryAmount()));
        flyerUpdatePayWallet.setSalaryFreeze(flyerWallet.getSalaryFreeze().subtract(flyerWalletFlowVO.getSalaryAmount()));
        int flyerUpdateCount = payWalletDao.updatePayWallet(flyerUpdatePayWallet);
        return flyerUpdateCount;
    }

    private void refund(PublisherWalletFlowVO publisherWalletFlowVO) {
        if (publisherWalletFlowVO.getRefundCashAmount().compareTo(BigDecimal.ZERO) != 0 || publisherWalletFlowVO.getRefundSalaryAmount().compareTo(BigDecimal.ZERO) != 0) {
            PayLogDO publishPayLogDO = buildPayLogDO(publisherWalletFlowVO, null);
            publishPayLogDO.setCashAmtPaid(publisherWalletFlowVO.getRefundCashAmount());
            publishPayLogDO.setSalaryAmtPaid(publisherWalletFlowVO.getRefundSalaryAmount());
            payWalletDao.insertPayLogDO(publishPayLogDO);
        }
    }

    private int addFlyerSalary(PublisherWalletFlowVO publisherWalletFlowVO, FlyerWalletFlowVO flyerWalletFlowVO, PayWalletDO flyerWallet) {
        assert flyerWalletFlowVO != null;
        PayWalletDO flyerPayWalletDO = new PayWalletDO();
        flyerPayWalletDO.setUserAccountId(flyerWalletFlowVO.getUserAccountId());
        flyerPayWalletDO.setPid(flyerWallet.getPid());
        flyerPayWalletDO.setSalaryAmt(flyerWallet.getSalaryAmt().add(publisherWalletFlowVO.getFlyerSalaryAmount()).add(flyerWalletFlowVO.getSalaryAmount()));
        flyerPayWalletDO.setSalaryFreeze(flyerWallet.getSalaryFreeze().subtract(flyerWalletFlowVO.getSalaryAmount()));
        flyerPayWalletDO.setCashAmt(flyerWallet.getCashAmt().add(flyerWalletFlowVO.getCashAmount()));
        flyerPayWalletDO.setCashFreeze(flyerWallet.getCashFreeze().subtract(flyerWalletFlowVO.getCashAmount()));
        int flyerUpdateCount = payWalletDao.updatePayWallet(flyerPayWalletDO);
        return flyerUpdateCount;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean releaseOrCancelOrderWallet(PublisherWalletFlowVO publisherWalletFlowVO, PayWalletDO wallet) {
        PayWalletDO publishUpdatePayWallet = new PayWalletDO();
        if (publisherWalletFlowVO.getCashAmount() == null) {
            publisherWalletFlowVO.setCashAmount(BigDecimal.ZERO);
        }
        if (publisherWalletFlowVO.getSalaryAmount() == null) {
            publisherWalletFlowVO.setSalaryAmount(BigDecimal.ZERO);
        }
        publishUpdatePayWallet.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
        publishUpdatePayWallet.setPid(wallet.getPid());
        publishUpdatePayWallet.setCashAmt(wallet.getCashAmt().add(publisherWalletFlowVO.getCashAmount()));
        publishUpdatePayWallet.setCashFreeze(wallet.getCashFreeze().subtract(publisherWalletFlowVO.getCashAmount()));
        publishUpdatePayWallet.setSalaryAmt(wallet.getSalaryAmt().add(publisherWalletFlowVO.getSalaryAmount()));
        publishUpdatePayWallet.setSalaryFreeze(wallet.getSalaryFreeze().subtract(publisherWalletFlowVO.getSalaryAmount()));
        int i = payWalletDao.updatePayWallet(publishUpdatePayWallet);
        if (i > 0) {
            return true;
        }
        return false;
    }

    public PayLogDO buildPayLogDO(PublisherWalletFlowVO publisherWalletFlowVO, FlyerWalletFlowVO flyerWalletFlowVO) {
        // 记录资金流水记录
        PayLogDO payLogWalletDO = new PayLogDO();
        // 获取用户钱包信息
        if (publisherWalletFlowVO != null) {
            // 生成支付流水号(规则"T" + 时间戳 + 用户id + 随机数4位)
            String publishPayNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + publisherWalletFlowVO.getUserAccountId() + CodeUtil.getRandomNum(4);
            payLogWalletDO.setPayMethod(publisherWalletFlowVO.getModeOfPayment());
            payLogWalletDO.setPayNo(publishPayNo);
            payLogWalletDO.setUserAccountId(publisherWalletFlowVO.getUserAccountId());
            payLogWalletDO.setCashAmtPaid(publisherWalletFlowVO.getCashAmount());
            payLogWalletDO.setSalaryAmtPaid(publisherWalletFlowVO.getSalaryAmount());
            payLogWalletDO.setPayTime(publisherWalletFlowVO.getTimeOfPayment());
            payLogWalletDO.setOperateUser(publisherWalletFlowVO.getOperateUserAccountId());
            return payLogWalletDO;
        }
        if (flyerWalletFlowVO != null) {
            if (flyerWalletFlowVO.getCashAmount() == null) {
                flyerWalletFlowVO.setCashAmount(BigDecimal.ZERO);
            }
            if (flyerWalletFlowVO.getSalaryAmount() == null) {
                flyerWalletFlowVO.setSalaryAmount(BigDecimal.ZERO);
            }
            // 生成支付流水号(规则"T" + 时间戳 + 用户id + 随机数4位)
            String flyerPayNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + flyerWalletFlowVO.getUserAccountId() + CodeUtil.getRandomNum(4);
            payLogWalletDO.setPayMethod(flyerWalletFlowVO.getModeOfPayment());
            payLogWalletDO.setPayNo(flyerPayNo);
            payLogWalletDO.setUserAccountId(flyerWalletFlowVO.getUserAccountId());
            payLogWalletDO.setCashAmtPaid(flyerWalletFlowVO.getCashAmount());
            payLogWalletDO.setSalaryAmtPaid(flyerWalletFlowVO.getSalaryAmount());
            payLogWalletDO.setPayTime(flyerWalletFlowVO.getTimeOfPayment());
            payLogWalletDO.setOperateUser(flyerWalletFlowVO.getOperateUserAccountId());
            return payLogWalletDO;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBody feignTopUpCash(TopUpOrderVO topUpOrderVO) {
        // 获取用户openid查询到用户信息
        UserAccountDO userAccountDO = userServiceDao.getUserAccountInfoByOpenId(topUpOrderVO.getOpenid());
        // 根据金额转成元
        BigDecimal topUpAmount = BigDecimal.valueOf(topUpOrderVO.getAmount()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
        // 根据用户id获取钱包金额信息
        PayWalletDO wallet = payWalletDao.getPayWalletByUser(userAccountDO.getId());
        // 修改云享金信息
        PayWalletDO payWalletDO = new PayWalletDO();
        payWalletDO.setCashAmt(wallet.getCashAmt().add(topUpAmount));
        payWalletDO.setPid(wallet.getPid());
        payWalletDO.setUserAccountId(userAccountDO.getId());
        int i = payWalletDao.updatePayWallet(payWalletDO);
        if (i > 0) {
            // 记录钱包流水
            PayLogDO payLogDO = new PayLogDO();
            payLogDO.setUserAccountId(userAccountDO.getId());
            payLogDO.setPayNo(topUpOrderVO.getOrderNo());
            payLogDO.setPayMethod(PayMethodEnums.USER_TOP_UP.getCode());
            payLogDO.setCashAmtPaid(topUpAmount);
            payLogDO.setOperateUser(userAccountDO.getId());
            payWalletDao.insertPayLogDO(payLogDO);
            return ResultBody.success();
        } else {
            return ResultBody.error("充值时钱包操作错误！");
        }
    }

    @Override
    public ResultBody customerBillingDetail(Integer userAccountId, WalletFlowQO param) {
        param.setUserAccountId(userAccountId);
        int count = payWalletDao.countPayLog(param);
        if (count == 0) {
            return ResultBody.success(PageResult.buildPage(param.getPageNo(), param.getPageSize(), count));
        }
        if (!StringUtils.isBlank(param.getYearMonth())) {
            param.setEndTime(TDateUtil.getDateStr(
                    TDateUtil.getMonthLatestDay(TDateUtil.getDate(param.getYearMonth() + "-01", "yyyy-MM-dd")),
                    "yyyy-MM-dd") + " 23:59:59");
        }
        Integer pageNo = param.getPageNo();
        param.buildCurrentPage();
        List<PayLogDO> payLogList = payWalletDao.getPayLog(param);
        return ResultBody.success(PageResult.buildPage(pageNo, param.getPageSize(), count, payLogList.stream().map(PayLogDO::buildUserBillingDetailVO).collect(Collectors.toList())));
    }

    @Override
    public ResultBody billingDetails(Integer id, String detailType) {
        if (WithdrawalInfoVO.AMT.equals(detailType)) {
            PayLogDO payLogDO = payWalletDao.getPayLogById(id);
            return ResultBody.success(payLogDO.buildUserBillingDetailVO());
        } else {
            XzWithdrawalApplyDO apply = payWalletDao.getWithdrawalApplyByIdOrOuterTradeNo(id, null);
            UserBillingDetailVO detail = apply.buildUserBillingDetailVO();
            List<WithdrawalLogDO> rebates = payWalletDao.listPayWithdrawalLog(apply.getId());
            detail.buildSchedules(rebates);
            return ResultBody.success(detail);
        }
    }

    @Override
    public ResultBody payUavWallet(PayUavWalletVO payUavWalletVO) {
        // 获取用户钱包信息
        PayWalletDO userWalletInfo = payWalletDao.getPayWalletByUser(payUavWalletVO.getUserAccountId());
        // 获取下单金额是否大于该用户钱包金额
        if (userWalletInfo.getCashAmt().compareTo(payUavWalletVO.getCashAmount()) < 0) {
            return ResultBody.error("可抵扣的云享金不足");
        }
        if (userWalletInfo.getSalaryAmt().compareTo(payUavWalletVO.getSalaryAmount()) < 0) {
            return ResultBody.error("可抵扣的佣金不足");
        }
        String payNo = "T" + TDateUtil.getDateStr(new Date(), TDateUtil.TYPE) + payUavWalletVO.getUserAccountId() + CodeUtil.getRandomNum(4);
        // 记录流水用户钱包流水记录
        PayLogDO payLogDO = new PayLogDO();
        payLogDO.setUserAccountId(payUavWalletVO.getUserAccountId());
        payLogDO.setPayNo(payNo);
        payLogDO.setOperateUser(payUavWalletVO.getUserAccountId());

        // 创建用户钱包
        PayWalletDO payWalletDO = new PayWalletDO();
        payWalletDO.setPid(userWalletInfo.getPid());
        payWalletDO.setUserAccountId(payUavWalletVO.getUserAccountId());
        // 判断当前订单状态是什么类型
        if (payUavWalletVO.getOrderStatus().equals(PayMethodEnums.PUBLISH_ORDER.getCode())) {
            payLogDO.setPayMethod(payUavWalletVO.getOrderStatus());
            if (payUavWalletVO.getCashAmount().compareTo(BigDecimal.ZERO) > 0) {
                payLogDO.setCashAmtPaid(payUavWalletVO.getCashAmount().negate());
            } else {
                payLogDO.setCashAmtPaid(BigDecimal.ZERO);
            }
            if (payUavWalletVO.getSalaryAmount().compareTo(BigDecimal.ZERO) > 0) {
                payLogDO.setSalaryAmtPaid(payUavWalletVO.getSalaryAmount().negate());
            } else {
                payLogDO.setSalaryAmtPaid(BigDecimal.ZERO);
            }
            // 如果是100 扣减余额冻结金额
            payWalletDO.setCashAmt(userWalletInfo.getCashAmt().subtract(payUavWalletVO.getCashAmount()));
            payWalletDO.setCashFreeze(userWalletInfo.getCashAmt().add(payUavWalletVO.getCashAmount()));
            payWalletDO.setSalaryAmt(userWalletInfo.getSalaryAmt().subtract(payUavWalletVO.getSalaryAmount()));
            payWalletDO.setSalaryFreeze(userWalletInfo.getSalaryAmt().add(payUavWalletVO.getSalaryAmount()));
        } else {
            payLogDO.setPayMethod(payUavWalletVO.getOrderStatus());
            payLogDO.setCashAmtPaid(payUavWalletVO.getCashAmount());
            payLogDO.setSalaryAmtPaid(payUavWalletVO.getSalaryAmount());
            // 如果是1400 回滚解冻金额
            payWalletDO.setCashAmt(userWalletInfo.getCashAmt().add(payUavWalletVO.getCashAmount()));
            payWalletDO.setCashFreeze(userWalletInfo.getCashAmt().subtract(payUavWalletVO.getCashAmount()));
            payWalletDO.setSalaryAmt(userWalletInfo.getSalaryAmt().add(payUavWalletVO.getSalaryAmount()));
            payWalletDO.setSalaryFreeze(userWalletInfo.getSalaryAmt().subtract(payUavWalletVO.getSalaryAmount()));
        }
        payWalletDao.insertPayLogDO(payLogDO);
        payWalletDao.updatePayWallet(payWalletDO);
        return ResultBody.success();
    }
}
