package cn.ysk.cashier.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.ysk.cashier.dto.ShopSummaryDto;
import cn.ysk.cashier.dto.BaseQueryDto;
import cn.ysk.cashier.dto.shop.ShopTableSaleInfoDto;
import cn.ysk.cashier.enums.PayTypeEnum;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.mapper.TbShopUserFlowMapper;
import cn.ysk.cashier.mybatis.service.TbShopUserFlowService;
import cn.ysk.cashier.repository.order.TbOrderDetailRepository;
import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
import cn.ysk.cashier.repository.shop.TbShopTableRepository;
import cn.ysk.cashier.repository.shop.TbShopUserRepository;
import cn.ysk.cashier.service.SummaryService;
import cn.ysk.cashier.utils.DateUtil;
import cn.ysk.cashier.utils.FileUtil;
import cn.ysk.cashier.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class SummaryServiceImpl implements SummaryService {
    @Resource
    private TbShopUserRepository tbShopUserRepository;
    @Resource
    private TbOrderInfoRepository tbOrderInfoRepository;
    @Resource
    private TbOrderDetailRepository detailRepository;

    @Autowired
    private TbShopUserFlowMapper tbShopUserFlowMapper;
    @Resource
    private TbShopUserFlowService tbShopUserFlowService;

    @Autowired
    private TbOrderDetailRepository tbOrderDetailRepository;
    private final TbShopTableRepository tbShopTableRepository;


    @Override
    public Map<String, Object> trade(BaseQueryDto param) {
        if (ObjectUtil.isNull(param.getShopId())) {
            throw new BadRequestException("参数不合法");
        }

        Map<String, Object> result = new HashMap<>();
        Map<String, Object> sale = new HashMap<>();
        Map<String, Object> vip = new HashMap<>();
        Map<String, Object> count = new HashMap<>();
        //订单 销售金额 saleAmount /订单数 saleNum /优惠金额 saveAmount /优惠笔数 saveNum
        Map<String, Object> orderMap = tbOrderInfoRepository.tradeIndex(param.getShopId(), param.getStartTime().getTime(), param.getEndTime().getTime());
        //退款金额
        BigDecimal refundAmount = tbOrderInfoRepository.tradeIndexRefund(param.getShopId(), param.getStartTime().getTime(), param.getEndTime().getTime());

        //会员 充值金额 inAmount /退款金额 outAmount /会员消费金额 useAmount /会员消费笔数 useNum
        Map<String, Object> flowMap = tbShopUserFlowMapper.tradeIndexFlow(param.getShopId(), DateUtil.getStrTime(param.getStartTime()), DateUtil.getStrTime(param.getEndTime()));
        // 新增会员数
        Integer newFlow = tbShopUserRepository.newFlow(param.getShopId().toString(), param.getStartTime(), param.getEndTime());
//        Integer newFlow = tbShopUserFlowMapper.tradeIndexNewFlow(param.getShopId(), DateUtil.getStrTime(param.getStartTime()), DateUtil.getStrTime(param.getEndTime()));
        //台桌数
        int tables = tbShopTableRepository.countAllByShopId(param.getShopId());
        //收款金额
        BigDecimal incomeAmount = new BigDecimal(orderMap.get("saleAmount").toString()).subtract(new BigDecimal(orderMap.get("saveAmount").toString()));//订单金额 - 优惠金额
        sale.put("totalSaleAmount", incomeAmount.add(refundAmount));//总金额 销售收款金额＋销售退款金额
        sale.put("incomeAmount", incomeAmount);//销售 收款金额
        sale.put("refundAmount", refundAmount);//销售 退款金额

        sale.put("totalVipAmount", new BigDecimal(flowMap.get("inAmount").toString()).add(new BigDecimal(flowMap.get("outAmount").toString())));//会员总金额
        sale.put("inAmount", flowMap.get("inAmount")); //会员 充值金额
        sale.put("outAmount", flowMap.get("outAmount"));//会员 退款金额

        sale.put("incomeAmountAll",incomeAmount);//总实收 销售实收
        List<TbOrderPayCountVo> payCountVos = initPaysCount();
        List<TbOrderPayCountVo> payCounts = tbOrderInfoRepository.queryTbOrderPayCount(
                param.getShopId().toString(), null, param.getStartTime().getTime(), param.getEndTime().getTime());
        Map<String, BigDecimal> payCountMap = payCounts.stream()
                .collect(Collectors.toMap(
                        TbOrderPayCountVo::getPayType,
                        vo -> {
                            BigDecimal payAmount = new BigDecimal(vo.getPayAmount().toString());
                            BigDecimal saveAmount = new BigDecimal(vo.getSaveAmount().toString());
                            return payAmount.subtract(saveAmount);
                        },
                        BigDecimal::add
                ));
        BigDecimal vipSaveAmount = tbShopUserFlowService.sumUserFlowAmountByConditions(
                param.getShopId().longValue(), DateUtil.getStrTime(param.getStartTime()), DateUtil.getStrTime(param.getEndTime()));
        for (TbOrderPayCountVo payCountVo : payCountVos) {
            BigDecimal payAmount = new BigDecimal(payCountVo.getPayAmount().toString());
            switch (payCountVo.getPayType()){
                case "微信小程序":
                    payCountVo.setPayAmount(payCountMap.containsKey("wx_lite")?payAmount.add(payCountMap.get("wx_lite")):payAmount);
                    break;
                case "支付宝小程序":
                    payCountVo.setPayAmount(payCountMap.containsKey("ali_lite")?payAmount.add(payCountMap.get("ali_lite")):payAmount);
                    break;
                case "主扫收款":
                    payCountVo.setPayAmount(payCountMap.containsKey("scanCode")?payAmount.add(payCountMap.get("scanCode")):payAmount);
                    break;
                case "收款码收款":
                    if(payCountMap.containsKey("ALIPAY")){
                        payAmount = payAmount.add(payCountMap.get("ALIPAY"));
                    }
                    if(payCountMap.containsKey("WECHAT")){
                        payAmount = payAmount.add(payCountMap.get("WECHAT"));
                    }
                    payCountVo.setPayAmount(payAmount);
                    break;
                case "现金":
                    payCountVo.setPayAmount(payCountMap.containsKey("cash")?payAmount.add(payCountMap.get("cash")):payAmount);
                    break;
                case "会员":
                    payCountVo.setPayAmount(payCountMap.containsKey("deposit")?payAmount.add(payCountMap.get("deposit")):payAmount);
                    break;
                case "充值":
                    payCountVo.setPayAmount(payAmount.add(vipSaveAmount));
                    break;
            }
        }
        sale.put("payCount",payCountVos);
        result.put("sale",sale);
        vip.put("useAmount", flowMap.get("useAmount"));//会员消费金额
        vip.put("newFlow",newFlow);//新增会员数
        vip.put("useNum",flowMap.get("useNum"));//会员消费笔数
        result.put("vip",vip);
        BigDecimal saleAmount = new BigDecimal(orderMap.get("saleAmount").toString()).subtract(new BigDecimal(orderMap.get("saveAmount").toString()));
        //客单价
        if(saleAmount.compareTo(BigDecimal.ZERO) == 0){
            count.put("unitPrice",BigDecimal.ZERO);
        }else {
            count.put("unitPrice",saleAmount.divide(new BigDecimal(orderMap.get("saleNum").toString()),2,RoundingMode.DOWN));
        }
        BigDecimal saleNum = new BigDecimal(orderMap.get("saleNum").toString());
        if(saleNum.compareTo(BigDecimal.ZERO) == 0 || saleNum.compareTo(new BigDecimal(tables)) < 0){
            count.put("turnoverRate","0%");//翻台率
        }else {
            BigDecimal turnoverRate = saleNum.divide(new BigDecimal(tables), 4, RoundingMode.DOWN).subtract(BigDecimal.ONE)
                    .multiply(new BigDecimal("100"));
            count.put("turnoverRate", turnoverRate.setScale(2, RoundingMode.DOWN) + "%");
        }
        count.put("saveAmount",orderMap.get("saveAmount"));//优惠金额
        count.put("saveNum",orderMap.get("saveNum"));//优惠单数
        result.put("count",count);
        return result;
    }

    public List<TbOrderPayCountVo> initPaysCount(){
        List<TbOrderPayCountVo> payCountVos = new ArrayList<>();
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/wx.png","微信小程序","1",BigDecimal.ZERO));
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/ali.png","支付宝小程序","1",BigDecimal.ZERO));
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/scan.png","主扫收款","1",BigDecimal.ZERO));
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/bscan.png","收款码收款","1",BigDecimal.ZERO));
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/cash.png","现金","1",BigDecimal.ZERO));
        payCountVos.add(new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/static/vipIn.png","充值","1",BigDecimal.ZERO));
//      payCountVos.add(new TbOrderPayCountVo("","会员支付","1",BigDecimal.ZERO));
        return payCountVos;
    }



    @Override
    public Map<String, Object> productSaleDate(Integer shopId, Integer day,Integer page,Integer size) {
        Pageable pageable = PageRequest.of(page, size);
        Date startTime = new Date();
        Date endTime = new Date();
        if (day == 7) {
            startTime = DateUtil.getDate7DaysAgo();
            endTime = DateUtil.getDayEnd();
        } else if (day == 30) {
            startTime = DateUtil.getDate30DaysAgo();
            endTime = DateUtil.getDayEnd();
        } else if (day == 360) {
            startTime = DateUtil.getBeginDayOfYear();
            endTime = DateUtil.getDateOneYearAgo();
        } else if (day == 1) {
            startTime = DateUtil.getDayBegin();
            endTime = DateUtil.getDayEnd();
        }
        HashMap<String, Object> map = new HashMap<>();
        Page<TbOrderSalesCountByDayVo> tbOrderSalesCountByDayVos = detailRepository.queryTbOrderSalesCountByDay(shopId, null, null, startTime, endTime,pageable);
        TbOrderSalesCountByDayVo tbOrderSalesCountByDayVo = detailRepository.queryTbOrderSalesCountByDaysummaryCount(shopId, null, null, startTime, endTime);
        TbOrderPayCountVo zong =new TbOrderPayCountVo("el-icon-coin","总金额","1",tbOrderSalesCountByDayVo.getSalesAmount());
        TbOrderPayCountVo xiaoliang =new TbOrderPayCountVo("el-icon-goods","销售量","0",tbOrderSalesCountByDayVo.getSalesNum());
        List<CountStockByDayVo> countStockByDayVos = tbOrderDetailRepository.countStockByDay(shopId, startTime, endTime);
        map.put("productCount", xiaoliang);
        map.put("productSum", zong);
        map.put("countList", countStockByDayVos) ;
        map.put("productList", tbOrderSalesCountByDayVos);
        return map;
    }


    @Override
    public Map<String, Object> selectSummaryAmount(Integer shopId, Integer day) {
        HashMap<String, Object> map = new HashMap<>();
        Date startTime;
        Date endTime;
        if (day == 7) {
            startTime = DateUtil.getDate7DaysAgo();
            endTime = DateUtil.getDayEnd();
        } else if (day == 30) {
            startTime = DateUtil.getDate30DaysAgo();
            endTime = DateUtil.getDayEnd();
        } else {
            throw new BadRequestException("日期有误");
        }

        List<Object[]> objects = tbOrderInfoRepository.queryTbOrderPaySumByDay(shopId.toString(), startTime, endTime);

        //根据时间的销量
        Map<String, SumDateVO> dataMap = new HashMap<>();
        for (Object[] o : objects) {
            SumDateVO sumDateVO = new SumDateVO();
            sumDateVO.setOrderAmount((BigDecimal) o[0]);
            sumDateVO.setTradeDay((String) o[1]);
            sumDateVO.setDiscountAmount((BigDecimal) o[2]);
            sumDateVO.setActualAmount(sumDateVO.getOrderAmount().subtract(sumDateVO.getDiscountAmount()));
            dataMap.put(sumDateVO.getTradeDay(), sumDateVO);
        }

        // 获取今天的日期
        LocalDate today = LocalDate.now();
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 转换为字符串
        List<SumDateVO> sumDateList = new ArrayList<>();
        for (int i = 0; i < day; i++) {
            LocalDate tradeDayLocalDate = today.minusDays(i);
            String tradeDayString = tradeDayLocalDate.format(formatter);
            SumDateVO sumDateVO;
            // 检查数据Map中是否存在该日期的数据
            if (dataMap.containsKey(tradeDayString)) {
                sumDateVO = dataMap.get(tradeDayString);
            } else {
                // 如果不存在，则创建新的SumDateVO对象，amount设为0
                sumDateVO = new SumDateVO(tradeDayString, BigDecimal.ZERO,BigDecimal.ZERO, BigDecimal.ZERO);
            }
            // 将SumDateVO对象添加到列表中
            sumDateList.add(sumDateVO);
        }
        sumDateList.sort(Comparator.comparing(SumDateVO::getTradeDay));
        map.put("total", sumDateList);
        return map;
    }


    @Override
    public Map<String, Object> selectSummaryPayType(Integer shopId, Integer day) {
        long startTime;
        long endTime;
        if (day == 7) {
            startTime = DateUtil.getSevenDaysAgoInMilliseconds();
            endTime = DateUtil.getTodayEndTimestamp();
        } else if (day == 30) {
            startTime = DateUtil.getThirtyDaysAgoInMilliseconds();
            endTime = DateUtil.getTodayEndTimestamp();
        } else if (day == 360) {
            startTime = DateUtil.getBeginningOfYearInMilliseconds();
            endTime = DateUtil.getEndOfYearInMilliseconds();
        } else {
            throw new BadRequestException("日期有误");
        }
        List<Object[]> countPayTypeMappings = tbOrderInfoRepository.countByShopId(shopId.toString(), startTime, endTime);
        List<CountPayTypeVO> countPayTypeVOList = new ArrayList<>();
        for (Object[] o : countPayTypeMappings) {
            CountPayTypeVO countPayTypeVO = new CountPayTypeVO();
            countPayTypeVO.setCount((BigInteger) o[0]);
            countPayTypeVO.setPayType(PayTypeEnum.getCodeByName((String) o[1]));
            countPayTypeVOList.add(countPayTypeVO);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("countPayType", countPayTypeVOList);
        return map;
    }


    @Override
    public List<TbOrderPayCountVo> summaryCount(ShopSummaryDto summaryDto) {
        List<TbOrderPayCountVo> list = new ArrayList<>();

        if (summaryDto.getStartTime() == null) {
            summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
            summaryDto.setEndTime(new Date());

        }

        TbOrderSalesCountByDayVo tbOrderSalesCountByDayVo = detailRepository.queryTbOrderSalesCountByDaysummaryCount(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime());
        TbOrderPayCountVo zongShuLiang = new TbOrderPayCountVo("el-icon-goods", "总数量", "0", tbOrderSalesCountByDayVo.getSalesNum() + tbOrderSalesCountByDayVo.getRefNum());
        TbOrderPayCountVo zong = new TbOrderPayCountVo("el-icon-coin", "总金额", "1", tbOrderSalesCountByDayVo.getSalesAmount());
        TbOrderPayCountVo tuidan = new TbOrderPayCountVo("el-icon-goods", "退单量", "0", tbOrderSalesCountByDayVo.getRefNum());
        TbOrderPayCountVo tuikuan = new TbOrderPayCountVo("el-icon-money", "退款金额", "1", tbOrderSalesCountByDayVo.getRefAmount());
//            TbOrderPayCountVo xiaoliang =new TbOrderPayCountVo("el-icon-goods","销售量","0",tbOrderSalesCountByDayVo.getSalesNum());

        list.add(zong);
        list.add(tuikuan);
//            list.add(xiaoliang);
        list.add(zongShuLiang);
        list.add(tuidan);

        return list;
    }

    @Override
    public <T> Page<T> selectSummaryByDay(ShopSummaryDto summaryDto, Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page, size);
        if (StringUtils.isBlank(summaryDto.getCateId())) {
            summaryDto.setCateId(null);
        }

        if (summaryDto.getStartTime() == null || summaryDto.getEndTime() == null) {
            summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
            summaryDto.setEndTime(new Date());
        }
        Page<TbOrderSalesCountByDayV2Vo> products = detailRepository.queryTbOrderSalesCountByProduct(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime(), pageable);
        for (TbOrderSalesCountByDayV2Vo product : products) {
            List<TbOrderSalesCountByDayV2Vo> skus = detailRepository.queryTbOrderSalesCountBySku(Integer.valueOf(summaryDto.getShopId()), product.getProductId(), summaryDto.getStartTime(), summaryDto.getEndTime());
            product.setSkus(skus);
        }
        return (Page<T>)products;
    }

    @Override
    public void download(ShopSummaryDto summaryDto, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        if (StringUtils.isBlank(summaryDto.getCateId())) {
            summaryDto.setCateId(null);
        }
        if (summaryDto.getStartTime() == null || summaryDto.getEndTime() == null) {
            summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
            summaryDto.setEndTime(new Date());
        }

        List<TbOrderSalesCountByDayV2Vo> products = detailRepository.queryTbOrderSalesCountByProduct(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime());
        for (TbOrderSalesCountByDayV2Vo product : products) {
            if("sku".equals(product.getTypeEnum())){
                List<TbOrderSalesCountByDayV2Vo> skus = detailRepository.queryTbOrderSalesCountBySku(Integer.valueOf(summaryDto.getShopId()), product.getProductId(), summaryDto.getStartTime(), summaryDto.getEndTime());
                product.setSkus(skus);
            }
        }
        for (TbOrderSalesCountByDayV2Vo product : products) {
            if("sku".equals(product.getTypeEnum())){
                for (TbOrderSalesCountByDayV2Vo skus : product.getSkus()) {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("商品分类", product.getCateName());
                    map.put("商品名称", product.getName());
                    map.put("商品规格", StringUtils.isBlank(skus.getName()) ? "" : skus.getName());
                    map.put("销 售 额", skus.getSalesAmount());
                    map.put("退 单 额", skus.getRefAmount().compareTo(BigDecimal.ZERO) == 0 ? skus.getRefAmount() : "-" + skus.getRefAmount());
                    map.put("实际销量", skus.getSalesNum());
                    map.put("退 单 量", skus.getRefNum());
                    list.add(map);
                }
            }else {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("商品分类", product.getCateName());
                map.put("商品名称", product.getName());
                map.put("商品规格", "");
                map.put("销 售 额", product.getSalesAmount());
                map.put("退 单 额", product.getRefAmount().compareTo(BigDecimal.ZERO) == 0 ? product.getRefAmount() : "-" + product.getRefAmount());
                map.put("实际销量", product.getSalesNum());
                map.put("退 单 量", product.getRefNum());
                list.add(map);
            }
        }
        FileUtil.downloadExcel(list, response);
    }


    @Override
    public List<ShopTableSaleInfoVo> selectSummaryTable(Integer shopId, Date startTime, Date endTime) {
        List<ShopTableVo> tableVos = tbOrderInfoRepository.queryShopTableVoByShopId(shopId);

        long start = 1704038400000L;
        long end = Instant.now().toEpochMilli();
        if (startTime != null && endTime != null) {
            start = startTime.getTime();
            end = endTime.getTime();
        }

        List<ShopTableSaleInfoVo> saleInfoVo = tbOrderInfoRepository.queryShopTableSaleInfo(shopId.toString(), start, end);

        Map<String, ShopTableVo> tableMap = tableVos.stream()
                .collect(Collectors.toMap(ShopTableVo::getQrcode, Function.identity()));
        saleInfoVo.parallelStream().forEach(vo -> {
            ShopTableVo tableVo = tableMap.get(vo.getTableId());
            if (tableVo != null) {
                vo.setShopId(shopId);
                vo.setTableId(tableVo.getTableId());
                vo.setTableName(tableVo.getTableName());
                vo.setAreaId(tableVo.getAreaId());
                vo.setAreaName(tableVo.getAreaName());
            }
        });

        if (!saleInfoVo.isEmpty()) {
            saleInfoVo.sort((a, b) -> {
                // 先比较 orderAmount
                BigDecimal aAmount = a.getOrderAmount() == null ? BigDecimal.ZERO : new BigDecimal(a.getOrderAmount().toString());
                BigDecimal bAmount = b.getOrderAmount() == null ? BigDecimal.ZERO : new BigDecimal(b.getOrderAmount().toString());
                int compareAmount = bAmount.compareTo(aAmount);
                if (compareAmount != 0) {
                    return compareAmount;
                }

                // 如果 orderAmount 相等，再比较 orderCount
                Integer aCount = a.getOrderCount() == null ? 0 : Integer.parseInt(a.getOrderCount().toString());
                Integer bCount = b.getOrderCount() == null ? 0 : Integer.parseInt(b.getOrderCount().toString());

                return bCount - aCount;
            });
        }

        return saleInfoVo;
    }

    @Override
    public void downloadTableSaleInfo(ShopTableSaleInfoDto shopTableSaleInfoDto, HttpServletResponse response) throws IOException {
        if (shopTableSaleInfoDto.getStartTime() == null) {
            shopTableSaleInfoDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
        }

        if (shopTableSaleInfoDto.getEndTime() == null) {
            shopTableSaleInfoDto.setEndTime(new Date());
        }

        List<ShopTableSaleInfoVo> infoVos = selectSummaryTable(shopTableSaleInfoDto.getShopId(), shopTableSaleInfoDto.getStartTime(), shopTableSaleInfoDto.getEndTime());

        infoVos.add(new ShopTableSaleInfoVo(99999, shopTableSaleInfoDto.getShopId(), null, "", "收银台", null, null, null, null));

        List<TbOrderSalesCountByTable> countByTables = tbOrderDetailRepository.queryTbOrderSalesCountByTable(shopTableSaleInfoDto.getShopId(), shopTableSaleInfoDto.getStartTime(), shopTableSaleInfoDto.getEndTime());

        Map<String, List<TbOrderSalesCountByTable>> countByTableMap = countByTables.stream()
                .collect(Collectors.groupingBy(TbOrderSalesCountByTable::getTableId));


        // 比较 shopTableSaleInfoDto 的 startTime 和 endTime 是不是同一天
        boolean sameDay = cn.hutool.core.date.DateUtil.isSameDay(shopTableSaleInfoDto.getStartTime(), shopTableSaleInfoDto.getEndTime());

        String queryDate = cn.hutool.core.date.DateUtil.format(shopTableSaleInfoDto.getStartTime(), "yyyy-MM-dd");
        if (!sameDay) {
            queryDate += " 至 " + cn.hutool.core.date.DateUtil.format(shopTableSaleInfoDto.getEndTime(), "yyyy-MM-dd");
        }

        List<Map<String, Object>> list = new ArrayList<>();

        List<List<Integer>> mergeList = new ArrayList<>();
        Map<String, Integer> tableStartIndexMap = new HashMap<>();
        int rowIndex = 1;
        for (ShopTableSaleInfoVo all : infoVos) {
            List<TbOrderSalesCountByTable> tables = countByTableMap.get(all.getTableCode());
            if (tables == null) {
                continue;
            }

            BigDecimal total = BigDecimal.ZERO;
            for (TbOrderSalesCountByTable table : tables) {
                total = total.add(table.getSalesAmount().abs());
            }

            String tableCode = all.getTableName().toString();
            if (!tableStartIndexMap.containsKey(tableCode)) {
                tableStartIndexMap.put(tableCode, rowIndex);
            }

            for (TbOrderSalesCountByTable table : tables) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("日期", queryDate);
                map.put("台桌", all.getTableName());
                map.put("商品分类", table.getCateName());
                map.put("商品名称", table.getProductName());
                map.put("单位", table.getUnitName());
                map.put("商品规格", table.getProductSkuName());
                map.put("销量", table.getSalesNum());
                map.put("单价", table.getPrice());
                map.put("金额", table.getSalesAmount());
                map.put("销售额", total);
                map.put("退单量", table.getRefNum());
                map.put("退单额", table.getRefAmount());
                list.add(map);
                rowIndex++;
            }

            int start = tableStartIndexMap.get(tableCode);
            int end = rowIndex - 1;
            if (end - start > 0) {
                mergeList.add(Arrays.asList(start, end, 0, 0));
                mergeList.add(Arrays.asList(start, end, 1, 1));
                mergeList.add(Arrays.asList(start, end, 9, 9));
            }
        }

        List<String> keyList = new ArrayList<>();
        keyList.add("日期");
        keyList.add("台桌");
        keyList.add("商品分类");
        keyList.add("商品名称");
        keyList.add("单位");
        keyList.add("商品规格");
        keyList.add("销量");
        keyList.add("单价");
        keyList.add("金额");
        keyList.add("销售额");
        keyList.add("退单量");
        keyList.add("退单额");

        FileUtil.downloadAndMergeExcel(list, mergeList, keyList, response);
    }
}
