package com.sqx.modules.reconciliation.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sqx.common.constant.RedisKey;
import com.sqx.common.exception.SqxException;
import com.sqx.common.utils.DateUtils;
import com.sqx.common.utils.PageUtils;
import com.sqx.modules.app.entity.UserEntity;
import com.sqx.modules.errand.service.UserInfoService;
import com.sqx.modules.goods.entity.GoodsShop;
import com.sqx.modules.goods.service.GoodsShopService;
import com.sqx.modules.reconciliation.mapper.PlatformBillMapper;
import com.sqx.modules.reconciliation.model.CashOutRecordBO;
import com.sqx.modules.reconciliation.model.IndentOrderDataBO;
import com.sqx.modules.reconciliation.model.OrderDataBO;
import com.sqx.modules.reconciliation.model.PlatformBill;
import com.sqx.modules.reconciliation.model.PlatformBillDto;
import com.sqx.modules.reconciliation.model.RiderBillVo;
import com.sqx.modules.reconciliation.model.ShopBillVo;
import com.sqx.modules.reconciliation.model.ShopMoneyRecordBO;
import com.sqx.modules.reconciliation.model.SysGiftRecordBO;
import com.sqx.modules.reconciliation.model.UserMoneyBalanceBO;
import com.sqx.modules.reconciliation.service.PlatformBillService;
import com.sqx.modules.utils.excel.ExcelData;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;

/**
 * <p>
 * 对账管理表 服务实现类
 * </p>
 *
 * @author ceshi
 * @since 2025-02-27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PlatformBillServiceImpl extends ServiceImpl<PlatformBillMapper, PlatformBill> implements PlatformBillService {

    private final GoodsShopService goodsShopService;
    private final UserInfoService userInfoService;
    private final RedissonClient redissonClient;
    private final PlatformTransactionManager transactionManager;

    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


    @Override
    public void test(LocalDate date) {
        doGeneratePlatformBill(date);
    }

    @Override
    public void generatePlatformBill(LocalDate date, boolean cover) {
        RLock lock = redissonClient.getLock(RedisKey.PLATFORM_BILL_LOCK);
        lock.lock();
        try {
            // 判断有无当天数据,然后根据策略觉得是否执行覆盖数据还是直接退出
            LambdaQueryWrapper<PlatformBill> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(PlatformBill::getDayId, date);
            if (count(wrapper) > 0) {
                if (!cover) {
                    return;
                }
            }

            // 生成账单数据
            Collection<PlatformBill> platformBills = doGeneratePlatformBill(date);

            // 开启编程式事务，保存账单数据
            DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
            definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            definition.setTimeout(30);  // 超时时间30秒
            TransactionStatus status = transactionManager.getTransaction(definition);
            try {
                // 删除旧数据
                if (cover) remove(wrapper);
                // 保存最终结果
                saveBatch(platformBills);

                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                throw new SqxException("账单数据保存失败", e);
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * @return
     */
    @Override
    public int insertPlatformBill() {
        //当天开始时间
        String endTime= DateUtils.format(new Date(),"yyyy-MM-dd")+" 00:00:00";
        //对账账期
        String dayId= DateUtils.addDateDaysString(new Date(),-1,"yyyy-MM-dd");
        //前一天开始时间
        String startTime=dayId+" 00:00:00";
        //当前时间
        String now=DateUtils.format(new Date());
        //先删除防止重复生成
        baseMapper.delete(new QueryWrapper<PlatformBill>().eq("day_id",dayId));
        //导入商家和骑手对账
        Integer count1 =baseMapper.insertPlatformBill(dayId,startTime,endTime,now);
        log.info("导入商家和骑手对账:{}条",count1);
        //导入平台对账
        Integer count3 =baseMapper.insertTotalPlatformBill(dayId);
        //导入平台账期开始金额
        Integer count2=baseMapper.updatePlatFormStartMoney(dayId);
        log.info("导入商户账期开始金额:{}条",count2);
        //导入商家骑手账期开始金额
        Integer count4=baseMapper.updateRiderStartMoney(dayId);
        log.info("导入骑手、平台账期开始金额:{}条",count2);

        log.info("导入平台对账:{}条",count3);
        if(count1<1||count3<1){
            return 0;
        }
        return count3;
    }

    /**
     * @param platformBillDto
     * @return
     */
    @Override
    public PageUtils riderBill(PlatformBillDto platformBillDto) {
        Page<RiderBillVo> pages = new Page<>(platformBillDto.getPage(), platformBillDto.getLimit());
        IPage<RiderBillVo> page = baseMapper.riderBill(pages, platformBillDto);
        return new PageUtils(page);
    }

    /**
     * @param platformBillDto
     * @return
     */
    @Override
    public PageUtils shopBill(PlatformBillDto platformBillDto) {
        Page<ShopBillVo> pages = new Page<>(platformBillDto.getPage(), platformBillDto.getLimit());
        IPage<ShopBillVo> page = baseMapper.shopBill(pages, platformBillDto);
        return new PageUtils(page);
    }

    /**
     * @param platformBillDto
     * @return
     */
    @Override
    public PageUtils platformBill(PlatformBillDto platformBillDto) {
        Page<PlatformBill> pages = new Page<>(platformBillDto.getPage(), platformBillDto.getLimit());
        IPage<PlatformBill> page = baseMapper.platformBill(pages, platformBillDto);
        return new PageUtils(page);
    }

    /**
     * @param query
     * @return
     */
    @Override
    public ExcelData excelRiderBillList(PlatformBillDto query) {
        List<RiderBillVo> riderBillVoList=baseMapper.excelRiderBillList(query);
        ExcelData data = new ExcelData();
        data.setName("骑手对账");
        List<String> titleList= Arrays.asList(
                "骑手姓名",
                "骑手手机号",
                "骑手站点 ",
                "日期",
                "期初金额（元）",
                "收入（元）",
                "收入笔数",
                "提现金额",
                "提现手续费",
                "提现笔数",
                "期末金额（元）",
                "赠送骑手余额（元）",
                "总收益（元）");
        data.setTitles(titleList);
        List<List<Object>> rows = new ArrayList<>();
        for (RiderBillVo riderBillVo:riderBillVoList ){
            List<Object> row = new ArrayList<>();
            row.add(riderBillVo.getUserName());
            row.add(riderBillVo.getPhone());
            row.add(riderBillVo.getStationName());
            row.add(riderBillVo.getDayId());
            row.add(riderBillVo.getStartMoney());
            row.add(riderBillVo.getRevenue());
            row.add(riderBillVo.getRevenueCount());
            row.add(riderBillVo.getRiderPayouts());
            row.add(riderBillVo.getRiderPayoutsRates());
            row.add(riderBillVo.getRiderPayoutsCount());
            row.add(riderBillVo.getEndMoney());
            row.add(riderBillVo.getSysGiftAmount());
            row.add(riderBillVo.getTotalIncome());
            rows.add(row);
        }
        data.setRows(rows);
        return data;
    }

    /**
     * @param query
     * @return
     */
    @Override
    public ExcelData excelShopBillList(PlatformBillDto query) {
        List<ShopBillVo> shopBillVoList = baseMapper.excelShopBillList(query);

        List<List<Object>> rows = shopBillVoList.stream().map(shopBillVo -> {
            List<Object> row = new ArrayList<>();
            row.add(shopBillVo.getShopName());
            row.add(shopBillVo.getPhone());
            row.add(shopBillVo.getDayId());
            row.add(shopBillVo.getStartMoney());
            row.add(shopBillVo.getRevenue());
            row.add(shopBillVo.getRevenueCount());
            row.add(shopBillVo.getPlatformRates());
            row.add(shopBillVo.getShopPayouts());
            row.add(shopBillVo.getShopPayoutsRates());
            row.add(shopBillVo.getShopPayoutsCount());
            row.add(shopBillVo.getEndMoney());
            row.add(shopBillVo.getShopBalance());
            row.add(shopBillVo.getTotalIncome());
            row.add(shopBillVo.getPayMoney());
            row.add(shopBillVo.getRefundMoney());
            row.add(shopBillVo.getRefundCount());

            return row;
        }).collect(Collectors.toList());

        ExcelData data = new ExcelData();
        data.setName("商户对账");
        data.setTitles(ShopBillVo.getExcelHead());
        data.setRows(rows);
        return data;
    }

    /**
     * @param query
     * @return
     */
    @Override
    public ExcelData excelPlatformBillList(PlatformBillDto query) {
        List<PlatformBill> platformBills=baseMapper.excelPlatformBillList(query);
        ExcelData data = new ExcelData();
        data.setName("平台对账");
        List<String> titleList= Arrays.asList(
                "日期 ",
                "期初金额（元）",
                "收入（元）",
                "收入笔数",
                "平台抽成手续费",
                "商家提现金额",
                "商家提现手续费",
                "商家提现笔数",
                "骑手提现金额",
                "骑手提现手续费",
                "骑手提现笔数",
                "退款金额（元）",
                "退款笔数",
                "期末金额（元）"
                );
        data.setTitles(titleList);
        List<List<Object>> rows = new ArrayList<>();
        for (PlatformBill platformBill:platformBills ){
            List<Object> row = new ArrayList<>();
            row.add(platformBill.getDayId());
            row.add(platformBill.getStartMoney());
            row.add(platformBill.getRevenue());
            row.add(platformBill.getRevenueCount());
            row.add(platformBill.getPlatformRates());
            row.add(platformBill.getShopPayouts());
            row.add(platformBill.getShopPayoutsRates());
            row.add(platformBill.getShopPayoutsCount());
            row.add(platformBill.getRiderPayouts());
            row.add(platformBill.getRiderPayoutsRates());
            row.add(platformBill.getRiderPayoutsRates());
            row.add(platformBill.getRefundMoney());
            row.add(platformBill.getRefundCount());
            row.add(platformBill.getEndMoney());
            rows.add(row);
        }
        data.setRows(rows);
        return data;
    }

    /**
     * 生成指定日期的平台账单集合
     * @param date 需要生成账单的目标日期（日级账单）
     * @return 包含三种类型账单的集合：商户账单、骑手账单、平台汇总账单
     *           集合结构：[商户账单列表] + [骑手账单列表] + [平台汇总账单]
     */
    private Collection<PlatformBill> doGeneratePlatformBill(LocalDate date) {
        // 查询前一天账单
        LambdaQueryWrapper<PlatformBill> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(PlatformBill::getDayId, date.minusDays(1));
        List<PlatformBill> prePlatformBillDataS = list(queryWrapper);
        Map<String, PlatformBill> platformBillMap = prePlatformBillDataS.stream().collect(Collectors.toMap(e -> (e.getUserId() + "-" + e.getType()), Function.identity()));

        // 查询商户数据
        List<PlatformBill> shopPlatformBills = queryShopBill(date, platformBillMap);

        // 查询骑手数据
        List<PlatformBill> riderPlatformBills = queryRiderBill(date, platformBillMap);

        // 计算平台账单数据
        PlatformBill platformBills = calcPlatformBill(date, shopPlatformBills, riderPlatformBills, prePlatformBillDataS);

        // 清除骑手账单中临时存储的商户余额数据
        riderPlatformBills.forEach(e -> e.setShopBalance(null));

        // 合并商户、骑手账单数据
        Collection<PlatformBill> allPlatformBills = CollUtil.union(shopPlatformBills, riderPlatformBills, Arrays.asList(platformBills));

        return allPlatformBills;
    }

    /**
     * 计算平台账单数据
     *
     * @param date 账期
     * @param shopPlatformBills  商家账单数据
     * @param riderPlatformBills 骑手账单数据
     * @param prePlatformBills 前一天对账数据
     * @return 平台账单数据
     */
    private PlatformBill calcPlatformBill(LocalDate date, List<PlatformBill> shopPlatformBills, List<PlatformBill> riderPlatformBills, List<PlatformBill> prePlatformBills) {
        // 账期
        String accountPeriod = date.toString();

        PlatformBill platformBill = new PlatformBill();
        platformBill.setDayId(accountPeriod);
        // 平台对账
        platformBill.setType("0");

        // 平台总收入等于所有支付金额-退款金额
        platformBill.setRevenue(sum(shopPlatformBills, PlatformBill::getPayMoney).subtract(sum(shopPlatformBills, PlatformBill::getRefundMoney)));
        // 订单总笔数
        platformBill.setRevenueCount(sumInt(shopPlatformBills, PlatformBill::getRevenueCount));
        // 商家总提现金额
        platformBill.setShopPayouts(sum(shopPlatformBills, PlatformBill::getPayoutsOfSuccess));
        // 商家总提现手续费
        platformBill.setShopPayoutsRates(sum(shopPlatformBills, PlatformBill::getPayoutsRatesOfSuccess));
        // 商家提现笔数
        platformBill.setShopPayoutsCount(sumInt(shopPlatformBills, PlatformBill::getPayoutsCountOfSuccess));
        // 骑手总提现金额
        platformBill.setRiderPayouts(sum(riderPlatformBills, PlatformBill::getPayoutsOfSuccess));
        // 骑手总提现手续费
        platformBill.setRiderPayoutsRates(sum(riderPlatformBills, PlatformBill::getPayoutsRatesOfSuccess));
        // 骑手提现笔数
        platformBill.setRiderPayoutsCount(sumInt(riderPlatformBills, PlatformBill::getPayoutsCountOfSuccess));
        // 退款金额
        platformBill.setRefundMoney(sum(shopPlatformBills, PlatformBill::getRefundMoney));
        // 退款笔数
        platformBill.setRefundCount(sumInt(shopPlatformBills, PlatformBill::getRefundCount));
        // 平台抽成手续费
        platformBill.setPlatformRates(sum(shopPlatformBills, PlatformBill::getPlatformRates));

        // 初始金额等于前一天的期末金额，如果前一天没有平台账单，则初始金额等于所有商家账户余额和所有骑手账户余额
        Optional<PlatformBill> prePlatformBillOptional = prePlatformBills.stream().filter(e -> "0".equals(e.getType())).findFirst();
        if (prePlatformBillOptional.isPresent()) {
            platformBill.setStartMoney(prePlatformBillOptional.get().getEndMoney());
        } else {
            platformBill.setStartMoney(sum(shopPlatformBills, PlatformBill::getShopBalance).add(sum(riderPlatformBills, PlatformBill::getShopBalance)));
        }

        // 期末金额 = 期初金额 + 当天收入 - 商家当天提现金额（已转账和待转账） - 骑手当天提现金额（已转账+待转账+已拒绝）
        BigDecimal endMoney = platformBill.getStartMoney()
                .add(platformBill.getRevenue())
                .subtract(platformBill.getShopPayouts())
                .subtract(platformBill.getRiderPayouts());
        platformBill.setEndMoney(endMoney);

        return platformBill;
    }

    /**
     * 查询骑手指定日期账单数据
     *  从跑腿订单中获取：
     *      收入
     *      收入笔数
     *      总收益：等于当天收入
     *  从提现表中获取:
     *      提现金额
     *      提现手续费
     *      提现笔数
     *  从对账表中获取：
     *      期初金额：前一天的期末金额
     *  从用户钱包明细中获取：
     *      赠送骑手余额
     *  从用户信息表中获取：
     *      期末金额：用户余额
     *
     * @param date            账单日期
     * @param platformBillMap 前一天对账数据
     * @return 骑手对账信息
     */
    private List<PlatformBill> queryRiderBill(LocalDate date, Map<String, PlatformBill> platformBillMap) {
        // 账期
        String accountPeriod = date.toString();
        // 账期开始-截止时间
        String startTime = DTF.format(date.atTime(0, 0, 0));
        String endTime = DTF.format(date.atTime(0, 0, 0).plusDays(1));

        // 查询骑手数据
        List<UserEntity> riderInfos = userInfoService.getAllRiderInfo();
        List<Long> userIds = riderInfos.stream().map(UserEntity::getUserId).collect(Collectors.toList());

        // 查询跑腿订单数据
        List<IndentOrderDataBO> indentOrderDataBOS = baseMapper.getIndentOrderData(startTime, endTime);
        Map<Long, IndentOrderDataBO> indentOrderDataMap = indentOrderDataBOS.stream().collect(Collectors.toMap(IndentOrderDataBO::getUserId, Function.identity()));

        // 查询提现数据
        List<CashOutRecordBO> riderCashOutRecords = baseMapper.getRiderCashOutRecord(startTime, endTime);
        Map<Long, CashOutRecordBO> riderCashOutRecordMap = riderCashOutRecords.stream().collect(Collectors.toMap(CashOutRecordBO::getUserId, Function.identity()));

        // 查询订单赠送金额数据
        List<SysGiftRecordBO> sysGiftRecordBOS = baseMapper.getSysGiftRecord(startTime, endTime, userIds);
        Map<Long, SysGiftRecordBO> sysGiftRecordMap = sysGiftRecordBOS.stream().collect(Collectors.toMap(SysGiftRecordBO::getUserId, Function.identity()));

        return riderInfos.stream().map(riderInfo -> {
            PlatformBill platformBill = new PlatformBill();
            platformBill.setDayId(accountPeriod);
            platformBill.setUserId(riderInfo.getUserId());
            // 骑手对账
            platformBill.setType("2");

            IndentOrderDataBO indentOrderData = indentOrderDataMap.get(riderInfo.getUserId());
            if (ObjectUtil.isNotNull(indentOrderData)) {
                platformBill.setRevenue(indentOrderData.getTotalAmount());
                platformBill.setRevenueCount(indentOrderData.getOrderCount());
            } else {
                platformBill.setRevenue(BigDecimal.ZERO);
                platformBill.setRevenueCount(0);
            }

            CashOutRecordBO cashOutRecord = riderCashOutRecordMap.get(riderInfo.getUserId());
            if (ObjectUtil.isNotNull(cashOutRecord)) {
                platformBill.setRiderPayouts(cashOutRecord.getPayouts());
                platformBill.setRiderPayoutsRates(cashOutRecord.getPayoutsRates());
                platformBill.setRiderPayoutsCount(cashOutRecord.getPayoutsCount());

                platformBill.setPayoutsOfSuccess(cashOutRecord.getPayoutsOfSuccess());
                platformBill.setPayoutsRatesOfSuccess(cashOutRecord.getPayoutsRatesOfSuccess());
                platformBill.setPayoutsCountOfSuccess(cashOutRecord.getPayoutsCountOfSuccess());
            } else {
                platformBill.setRiderPayouts(BigDecimal.ZERO);
                platformBill.setRiderPayoutsRates(BigDecimal.ZERO);
                platformBill.setRiderPayoutsCount(0);

                platformBill.setPayoutsOfSuccess(BigDecimal.ZERO);
                platformBill.setPayoutsRatesOfSuccess(BigDecimal.ZERO);
                platformBill.setPayoutsCountOfSuccess(0);
            }

            SysGiftRecordBO sysGiftRecord = sysGiftRecordMap.get(riderInfo.getUserId());
            if (ObjectUtil.isNotNull(sysGiftRecord)) {
                platformBill.setSysGiftAmount(sysGiftRecord.getAmount());
            } else {
                platformBill.setSysGiftAmount(BigDecimal.ZERO);
            }

            platformBill.setTotalIncome(platformBill.getRevenue());

            // 临时存储骑手余额
            platformBill.setShopBalance(riderInfo.getBalance());


            PlatformBill preBill = platformBillMap.get(riderInfo.getUserId() + "-2");

            // 期初金额 = 前一天期末金额
            // 期末金额 = 期初金额 + 当天收入 - 当天提现金额 - 当天提现手续费 + 当天骑手赠送余额
            // 如果前一天对账数据为空，则期初金额为骑手账户余额
            if (ObjectUtil.isNotNull(preBill)) {
                platformBill.setStartMoney(preBill.getEndMoney());

                BigDecimal endMoney = preBill.getEndMoney()
                        .add(platformBill.getRevenue())
                        .subtract(platformBill.getRiderPayouts())
                        .subtract(platformBill.getRiderPayoutsRates())
                        .add(platformBill.getSysGiftAmount());
                platformBill.setEndMoney(endMoney);
            } else {
                platformBill.setStartMoney(BigDecimal.ZERO);
                platformBill.setEndMoney(riderInfo.getBalance());
            }

            return platformBill;
        }).collect(Collectors.toList());
    }

    /**
     * 查询商家指定日期账单数据
     *  从订单表中获取（当天数据）：
     *      用户实际付款：当天用户实际付款金额
     *      退款金额：当天退款金额
     *      退款笔数：当天退款笔数
     *      收入：当天商家收入
     *      收入笔数：当天商家收入笔数
     *  从商家钱包明细表中获取：
     *      总收益：当天的入账金额（等于订单表里的商家收入）
     *      平台抽成手续费：当天平台抽成金额
     *  从提现表中获取（当天数据）：
     *      提现金额：当天提现金额
     *      提现手续费：当天提现手续费
     *      提现笔数：当天提现笔数
     *  从用户信息表中获取：
     *      账户余额：截止统计时的用户账户余额
     *  从平台对账表中获取：
     *      期初金额：前一天的期末金额
     *  直接复用：
     *      期末金额：总收益
     *
     * @param date            账单日期
     * @param platformBillMap 前一天账单数据
     * @return 商家对账单信息
     */
    private List<PlatformBill> queryShopBill(LocalDate date, Map<String, PlatformBill> platformBillMap) {
        // 账期

        String accountPeriod = date.toString();
        // 账期开始-截止时间
        String startTime = DTF.format(date.atTime(0, 0, 0));
        String endTime = DTF.format(date.atTime(0, 0, 0).plusDays(1));

        // 获取店铺信息
        List<GoodsShop> goodsShops = goodsShopService.getAllShops();
        List<Long> userIds = goodsShops.stream().map(GoodsShop::getUserId).collect(Collectors.toList());

        // 统计订单信息
        List<OrderDataBO> orderDataBOs = baseMapper.getOrderData(startTime, endTime);
        Map<Long, OrderDataBO> orderDataMap = orderDataBOs.stream().collect(Collectors.toMap(OrderDataBO::getShopId, Function.identity()));

        // 查询当天平台抽成 抽成数据在user_money_details表中，订单完成时会计算商家收入、平台抽成
        List<ShopMoneyRecordBO> shopMoneyRecords = baseMapper.getShopMoneyRecord(startTime, endTime);
        Map<Long, ShopMoneyRecordBO> shopMoneryRecordMap = shopMoneyRecords.stream().collect(Collectors.toMap(ShopMoneyRecordBO::getShopId, Function.identity()));

        // 查询所有商家提现记录
        List<CashOutRecordBO> shopCashOutRecords = baseMapper.getShopCashOutRecord(startTime, endTime);
        Map<Long, CashOutRecordBO> cashOutRecordMap = shopCashOutRecords.stream().collect(Collectors.toMap(CashOutRecordBO::getUserId, Function.identity()));

        // 查询商户余额
        List<UserMoneyBalanceBO> userMoneyBalances = baseMapper.getUserMoneyBalance(userIds);
        Map<Object, UserMoneyBalanceBO> userMoneyBalanceMap = userMoneyBalances.stream().collect(Collectors.toMap(UserMoneyBalanceBO::getUserId, Function.identity()));

        // 拼装商家对账数据
        return goodsShops.stream().map(goodsShop -> {
            PlatformBill platformBill = new PlatformBill();
            platformBill.setDayId(accountPeriod);
            platformBill.setUserId(goodsShop.getUserId());
            platformBill.setShopName(goodsShop.getShopName());
            // 商户对账
            platformBill.setType("1");

            OrderDataBO orderData = orderDataMap.get(goodsShop.getShopId());
            if (ObjectUtil.isNotNull(orderData)) {
                platformBill.setRevenue(orderData.getShopAmount());
                platformBill.setRevenueCount(orderData.getCompletedCount());
                platformBill.setRefundMoney(orderData.getCanceledAmount());
                platformBill.setRefundCount(orderData.getCanceledCount());
                platformBill.setPayMoney(orderData.getPayAmount());
            } else {
                platformBill.setRevenue(BigDecimal.ZERO);
                platformBill.setRevenueCount(0);
                platformBill.setRefundMoney(BigDecimal.ZERO);
                platformBill.setRefundCount(0);
                platformBill.setPayMoney(BigDecimal.ZERO);
            }

            ShopMoneyRecordBO shopMoneyRecord = shopMoneryRecordMap.get(goodsShop.getShopId());
            if (ObjectUtil.isNotNull(shopMoneyRecord)) {
                platformBill.setPlatformRates(shopMoneyRecord.getPlatformFee());
            } else {
                platformBill.setPlatformRates(BigDecimal.ZERO);
            }

            CashOutRecordBO shopCashOutRecord = cashOutRecordMap.get(goodsShop.getUserId());
            if (ObjectUtil.isNotNull(shopCashOutRecord)) {
                platformBill.setShopPayouts(shopCashOutRecord.getPayouts());
                platformBill.setShopPayoutsRates(shopCashOutRecord.getPayoutsRates());
                platformBill.setShopPayoutsCount(shopCashOutRecord.getPayoutsCount());

                platformBill.setPayoutsOfSuccess(shopCashOutRecord.getPayoutsOfSuccess());
                platformBill.setPayoutsRatesOfSuccess(shopCashOutRecord.getPayoutsRatesOfSuccess());
                platformBill.setPayoutsCountOfSuccess(shopCashOutRecord.getPayoutsCountOfSuccess());
            } else {
                platformBill.setShopPayouts(BigDecimal.ZERO);
                platformBill.setShopPayoutsRates(BigDecimal.ZERO);
                platformBill.setShopPayoutsCount(0);

                platformBill.setPayoutsOfSuccess(BigDecimal.ZERO);
                platformBill.setPayoutsRatesOfSuccess(BigDecimal.ZERO);
                platformBill.setPayoutsCountOfSuccess(0);
            }

            UserMoneyBalanceBO userMoneyBalance = userMoneyBalanceMap.get(goodsShop.getUserId());
            if (ObjectUtil.isNotNull(userMoneyBalance)) {
                platformBill.setShopBalance(userMoneyBalance.getBalance());
            } else {
                platformBill.setShopBalance(BigDecimal.ZERO);
            }

            // 总收益等于完成订单收入
            platformBill.setTotalIncome(platformBill.getRevenue());

            // 期初金额 = 前一天的期末金额
            // 期末金额 = 期初金额 + 当天收入 - 当天提现金额 - 当天提现手续费
            // 如果前一天没有数据，则期初金额账户余额
            PlatformBill preBill = platformBillMap.get(goodsShop.getUserId() + "-1");
            if (ObjectUtil.isNotNull(preBill)) {
                platformBill.setStartMoney(preBill.getEndMoney());

                // 期末金额 = 期初金额 + 当天收入 - 当天提现金额 - 当天提现手续费
                BigDecimal endMoney = preBill.getEndMoney()
                        .add(platformBill.getRevenue())
                        .subtract(platformBill.getShopPayouts())
                        .subtract(platformBill.getShopPayoutsRates());

                platformBill.setEndMoney(endMoney);
            } else {
                platformBill.setStartMoney(BigDecimal.ZERO);
                platformBill.setEndMoney(platformBill.getShopBalance());
            }

            return platformBill;
        }).collect(Collectors.toList());
    }

    /**
     * 统计BigDecimal类型数值
     * @param bills 待统计数据
     * @param mapper 待统计字段
     * @return 统计结果
     */
    private static BigDecimal sum(List<PlatformBill> bills, Function<PlatformBill, BigDecimal> mapper) {
        return bills.stream().map(mapper).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 统计Integer类型数值
     * @param bills 待统计数据
     * @param mapper 待统计字段
     * @return 统计结果
     */
    private static int sumInt(List<PlatformBill> bills, ToIntFunction<PlatformBill> mapper) {
        return bills.stream().mapToInt(mapper).sum();
    }
}
