package cn.ysk.cashier.service.impl;

import cn.ysk.cashier.dto.ShopSummaryDto;
import cn.ysk.cashier.dto.shop.ExportTableStsDataDto;
import cn.ysk.cashier.dto.shop.ShopTableSaleInfoDto;
import cn.ysk.cashier.enums.PayTypeEnum;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.service.TbShopUserFlowService;
import cn.ysk.cashier.repository.ShopUserDutyDetailRepository;
import cn.ysk.cashier.repository.ShopUserDutyRepository;
import cn.ysk.cashier.repository.TbTokenRepository;
import cn.ysk.cashier.repository.order.TbOrderDetailRepository;
import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
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.utils.FileUtils;
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.persistence.Tuple;
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 ShopUserDutyRepository shopUserDutyRepository;
    @Resource
    private ShopUserDutyDetailRepository shopUserDutyDetailRepository;
    @Resource
    private TbShopUserRepository tbShopUserRepository;
    @Resource
    private TbOrderInfoRepository tbOrderInfoRepository;
    @Resource
    private TbOrderDetailRepository detailRepository;

    @Resource
    private TbTokenRepository tbTokenRepository;

    @Resource
    private TbShopUserFlowService tbShopUserFlowService;
    @Autowired
    private TbOrderDetailRepository tbOrderDetailRepository;


    @Override
    public SummaryVO selectSummary(Integer shopId) {
        SummaryVO summaryVO = new SummaryVO();
        //支付笔数,
        Tuple result = tbOrderInfoRepository.countByShopId(shopId.toString());
        summaryVO.setPaymentsNumber(result.get(0, Long.class) == null ? 0L : result.get(0, Long.class));
        summaryVO.setTotalSales(result.get(1, BigDecimal.class) == null ? new BigDecimal("0") : result.get(1, BigDecimal.class));
        if (summaryVO.getPaymentsNumber() == 0) {
            summaryVO.setAverageSales(new BigDecimal("0"));
        } else {
            summaryVO.setAverageSales(summaryVO.getTotalSales().divide(new BigDecimal(summaryVO.getPaymentsNumber()), 2, RoundingMode.DOWN));
        }
        //用户数
        Tuple count = tbShopUserRepository.searchByCount(shopId.toString());
        summaryVO.setTotalUser(count == null ? 0L : count.get(0, Long.class));
        //支付笔数柱形图
        List<Object[]> objects = tbOrderInfoRepository.sumByDateOrderNum(shopId.toString(), DateUtil.getDate30DaysAgo(), DateUtil.getDayEnd());
        List<CountDateVO> countDateList = new ArrayList<>();
        for (Object[] o : objects) {
            CountDateVO countDateVO = new CountDateVO();
            BigInteger integers = (BigInteger) o[0];
            countDateVO.setCount(new BigDecimal(integers.toString()));
            countDateVO.setTradeDay((String) o[1]);
            countDateList.add(countDateVO);
        }
        //填充日期
        Map<String, CountDateVO> dataMap = new HashMap<>();
        for (CountDateVO entry : countDateList) {
            String tradeDay = entry.getTradeDay();
            BigDecimal countOrder = entry.getCount();
            dataMap.put(tradeDay, new CountDateVO(tradeDay, countOrder));
        }
        // 获取今天的日期
        LocalDate today = LocalDate.now();
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 转换为字符串
        List<CountDateVO> countDateLists = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            LocalDate tradeDayLocalDate = today.minusDays(i);
            String tradeDayString = tradeDayLocalDate.format(formatter);
            CountDateVO countDateVO;
            // 检查数据Map中是否存在该日期的数据
            if (dataMap.containsKey(tradeDayString)) {
                countDateVO = dataMap.get(tradeDayString);
            } else {
                // 如果不存在，则创建新的SumDateVO对象，amount设为0
                countDateVO = new CountDateVO(tradeDayString, BigDecimal.ZERO);
            }
            // 将SumDateVO对象添加到列表中
            countDateLists.add(countDateVO);
        }
        countDateLists.sort((a, b) -> a.getTradeDay().compareTo(b.getTradeDay()));
        summaryVO.setCountDateList(countDateLists);
        //访问量
        Tuple tuple = tbTokenRepository.countByAccountId(shopId);
        summaryVO.setTotalVisits(tuple == null ? 0L : tuple.get(0, Long.class));
        //访问量柱状图
        List<Object[]> objectsVisits = tbTokenRepository.countByMonth(shopId, DateUtil.getDate30DaysAgo(), DateUtil.getDayEnd());
        List<CountVisitsVO> visitsList = new ArrayList<>();
        for (Object[] o : objectsVisits) {
            CountVisitsVO countDateVO = new CountVisitsVO();
            countDateVO.setCount((BigInteger) o[0]);
            countDateVO.setTradeDay((String) o[1]);
            visitsList.add(countDateVO);
        }
        //填充日期
        Map<String, CountVisitsVO> dataVisitsMap = new HashMap<>();
        for (CountVisitsVO entry : visitsList) {
            String tradeDay = entry.getTradeDay();
            BigInteger countOrder = entry.getCount();
            dataVisitsMap.put(tradeDay, new CountVisitsVO(tradeDay, countOrder));
        }
        // 转换为字符串
        List<CountVisitsVO> countVisitsLists = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            LocalDate tradeDayLocalDate = today.minusDays(i);
            String tradeDayString = tradeDayLocalDate.format(formatter);
            CountVisitsVO countDateVO;
            // 检查数据Map中是否存在该日期的数据
            if (dataVisitsMap.containsKey(tradeDayString)) {
                countDateVO = dataVisitsMap.get(tradeDayString);
            } else {
                // 如果不存在，则创建新的SumDateVO对象，amount设为0
                countDateVO = new CountVisitsVO(tradeDayString, BigInteger.ZERO);
            }
            // 将SumDateVO对象添加到列表中
            countVisitsLists.add(countDateVO);
        }
        countVisitsLists.sort((a, b) -> a.getTradeDay().compareTo(b.getTradeDay()));
        summaryVO.setVisitsCountList(countVisitsLists);
        return summaryVO;
    }

    @Override
    public Map<String, Object> selectSummaryDate(Integer shopId, Integer day) {
        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<>();
        Tuple tuple = detailRepository.sumByShopId(shopId, startTime, endTime);
        List<Object[]> objects = detailRepository.sumByShopIdGroup(shopId, startTime, endTime);
        //List<Object[]> objects = shopUserDutyDetailRepository.searchByDutyGroup(shopId, DateUtil.getDate30DaysAgo(), DateUtil.getDayEnd());
        List<CountDateVO> numList = new ArrayList<>();
        for (Object[] o : objects) {
            CountDateVO countDateVO = new CountDateVO();
            BigInteger integers = (BigInteger) o[1];
            countDateVO.setCount(new BigDecimal(integers.toString()));
            Date date = (Date) o[2];
            countDateVO.setTradeDay(date.toString());
            numList.add(countDateVO);
        }
        List<Object[]> objects2 = tbOrderInfoRepository.queryTbOrderPaySumByDay(shopId.toString(), startTime, endTime);
        List<CountDateVO> amountList = new ArrayList<>();
        for (Object[] o : objects2) {
            CountDateVO countDateVO = new CountDateVO();
            countDateVO.setCount((BigDecimal) o[0]);
            countDateVO.setTradeDay((String) o[1]);
            amountList.add(countDateVO);
        }
        map.put("productCount", tuple == null ? 0 : tuple.get(0, BigDecimal.class));
        map.put("productSum", tuple == null ? 0 : tuple.get(1, BigInteger.class));
        map.put("numList", numList);
        map.put("amountList", amountList);
        return map;
    }

    @Override
    public Map<String, Object> selectSummaryProduct(Integer shopId, Integer day, Integer currentPage, Integer currentSize) {
        //根据时间商品排行
        currentPage = (currentPage - 1) * currentSize;
        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 if (day == 360) {
            startTime = DateUtil.getBeginDayOfYear();
            endTime = DateUtil.getEndDayOfYear();
        } else if (day == 1) {

            startTime = DateUtil.getDayBegin();
            log.info("1天时间" + startTime.toString());
            endTime = DateUtil.getDayEnd();
            log.info("1天时间末" + endTime.toString());
        } else {
            throw new BadRequestException("日期有误");
        }
        Pageable pageable = PageRequest.of(0, 5);
        List<Object[]> objects = tbOrderInfoRepository.queryTbOrderPayCountByDayExt(shopId, startTime, endTime, currentPage, currentSize);

        List<ProductExtVO> list = new ArrayList<>();
        for (Object[] o : objects) {
            ProductExtVO productVO = new ProductExtVO();
            productVO.setProductId((BigInteger) o[0]);
            productVO.setProductName((String) o[1]);
            productVO.setProductNum((BigDecimal) o[2]);
            productVO.setAmount((BigDecimal) o[3]);
            list.add(productVO);
        }

        //分页数据
        Tuple tuple1 = detailRepository.searchCount(shopId, startTime, endTime);
        //销售数量
        Tuple payCount = detailRepository.sumByShopId(shopId, startTime, endTime);
        //销售金额
        Long startTimeLong = DateUtil.convertDateToTimestamp(startTime);
        Long endTimeLong = DateUtil.convertDateToTimestamp(endTime);
        Tuple paySum = tbOrderInfoRepository.queryPaySumByDayAll(shopId.toString(), startTimeLong, endTimeLong);

        map.put("productCount", payCount == null ? 0 : payCount.get(0, BigDecimal.class));
        map.put("productSum", paySum == null ? 0 : paySum.get(0, BigDecimal.class));
        map.put("totalProduct", list);
        map.put("total", tuple1 == null ? 0 : tuple1.get(0, BigInteger.class));
        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);

        //根据时间的销量
        List<SumDateVO> sumDateVOList = new ArrayList<>();
        for (Object[] o : objects) {
            SumDateVO sumDateVO = new SumDateVO();
            sumDateVO.setAmount((BigDecimal) o[0]);
            sumDateVO.setTradeDay((String) o[1]);
            sumDateVOList.add(sumDateVO);
        }
        //填充日期
        Map<String, SumDateVO> dataMap = new HashMap<>();
        for (SumDateVO entry : sumDateVOList) {
            String tradeDay = entry.getTradeDay();
            BigDecimal amount = entry.getAmount();
            dataMap.put(tradeDay, new SumDateVO(tradeDay, amount));
        }
        // 获取今天的日期
        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);
            }
            // 将SumDateVO对象添加到列表中
            sumDateList.add(sumDateVO);
        }
        sumDateList.sort((a, b) -> a.getTradeDay().compareTo(b.getTradeDay()));
        map.put("total", sumDateList);
        return map;
    }

    @Override
    public Map<String, Object> selectSummaryToday(Integer shopId) {
        HashMap<String, Object> map = new HashMap<>();
        Tuple tuple = tbOrderInfoRepository.sumByShopIdToday(shopId.toString(), DateUtil.getDayBegin(), DateUtil.getDayEnd());
        map.put("paymentsNumberToday", tuple == null ? 0L : tuple.get(0, BigInteger.class));
        map.put("totalSalesToday", tuple == null ? new BigDecimal("0") : tuple.get(1, BigDecimal.class));
        Tuple tuple1 = tbShopUserRepository.searchByCountToday(shopId.toString(), DateUtil.getTodayStartTimestamp(), DateUtil.getTodayEndTimestamp());
        map.put("userToday", tuple1.get(0, Long.class));
        Tuple tupleToday = tbTokenRepository.countByAccountId(shopId, DateUtil.getDayBegin(), DateUtil.getDayEnd());
        map.put("totalVisitsToday", tupleToday == null ? 0 : tupleToday.get(0, Long.class));
        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 <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.getType() != null && summaryDto.getType() == 1) {//金额
            Long start = 1704038400000L;
            Long end = Instant.now().toEpochMilli();
            if (summaryDto.getStartTime() != null && summaryDto.getEndTime() != null) {
                start = summaryDto.getStartTime().getTime();
                end = summaryDto.getEndTime().getTime();
            }
            Page<T> tPage = (Page<T>) tbOrderInfoRepository.queryTbOrderPayCountByDay(summaryDto.getShopId(), start, end, pageable);

            tPage.getContent().forEach(t -> {
                TbOrderPayCountByDayVo tbOrderPayCountByDayVo = (TbOrderPayCountByDayVo) t;

                BigDecimal recharge = tbShopUserFlowService.sumUserFlowAmountByConditions(Long.valueOf(summaryDto.getShopId()),
                        tbOrderPayCountByDayVo.getTradeDay() + " 00:00:00",
                        tbOrderPayCountByDayVo.getTradeDay() + " 23:59:59");
                tbOrderPayCountByDayVo.setRecharge(recharge);

                BigDecimal decimal = tbOrderInfoRepository.queryRefundOrderAmountByTradeDay(summaryDto.getShopId(), tbOrderPayCountByDayVo.getTradeDay());
                tbOrderPayCountByDayVo.setRefund(decimal == null ? new BigDecimal("0.00") : decimal);

                BigDecimal total = (BigDecimal) tbOrderPayCountByDayVo.getTotal();
                BigDecimal refund = (BigDecimal) tbOrderPayCountByDayVo.getRefund();
                tbOrderPayCountByDayVo.setTotal(total.subtract(refund));
            });

            return tPage;
        } else {//销量
            if (summaryDto.getStartTime() == null || summaryDto.getEndTime() == null) {
                summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
                summaryDto.setEndTime(new Date());
            }
            return (Page<T>) detailRepository.queryTbOrderSalesCountByDay(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime(), pageable);
        }
    }


    @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.getType() != null && summaryDto.getType() == 1) {//金额
            Long start = 1704038400000L;
            Long end = Instant.now().toEpochMilli();
            if (summaryDto.getStartTime() != null && summaryDto.getEndTime() != null) {
                start = summaryDto.getStartTime().getTime();
                end = summaryDto.getEndTime().getTime();
            }
            List<TbOrderPayCountByDayVo> tbOrderPayCountByDayVos = tbOrderInfoRepository.queryTbOrderPayCountByDay(summaryDto.getShopId(), start, end);
            for (TbOrderPayCountByDayVo all : tbOrderPayCountByDayVos) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("总金额", all.getTotal());
                map.put("现金", all.getCash());
                map.put("储值卡支付", all.getDeposit());
                map.put("扫码支付", all.getScanCode());
                map.put("微信小程序支付", all.getWxLite());
                map.put("日期", all.getTradeDay());
                list.add(map);
            }
        } else {//销量
            if (summaryDto.getStartTime() == null || summaryDto.getEndTime() == null) {
                summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
                summaryDto.setEndTime(new Date());
            }
            List<TbOrderSalesCountByDayVo> tbOrderSalesCountByDayVos = detailRepository
                    .queryTbOrderSalesCountByDay(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime());
            tbOrderSalesCountByDayVos.forEach(all -> {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("商品分类", all.getCateName());
                map.put("商品名称", all.getProductName());
                map.put("单   位", all.getUnitName());
                map.put("商品规格", StringUtils.isBlank(all.getProductSkuName()) ? "" : all.getProductSkuName());
                map.put("单   价", all.getPrice());
                map.put("销 售 额", all.getSalesAmount());
                map.put("退 单 额", all.getRefAmount().compareTo(BigDecimal.ZERO) == 0 ? all.getRefAmount() : "-" + all.getRefAmount());
                map.put("总 销 量", all.getNum() - all.getRefNum());
                map.put("实际销量", all.getSalesNum());
                map.put("退 单 量", all.getRefNum());
                list.add(map);
            });

        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<TbOrderPayCountVo> summaryCount(ShopSummaryDto summaryDto) {
        List<TbOrderPayCountVo> list = new ArrayList<>();
        Long start = 1704038400000L;
        Long end = Instant.now().toEpochMilli();
        if (summaryDto.getStartTime() != null || summaryDto.getEndTime() != null) {
            start = summaryDto.getStartTime().getTime();
            end = summaryDto.getEndTime().getTime();
        } else {
            summaryDto.setStartTime(DateUtil.toDate(DateUtil.fromTimeStamp(1704038400L)));
            summaryDto.setEndTime(new Date());
        }
        if (summaryDto.getType() != null && summaryDto.getType() == 1) {
            TbOrderPayCountVo payCount = tbOrderInfoRepository.queryOrderPayCount(summaryDto.getShopId(), start, end);
            TbOrderPayCountVo refCount = tbOrderInfoRepository.queryTbOrderRefund(summaryDto.getShopId(), null,start, end);
            payCount.setPayAmount(new BigDecimal(payCount.getPayAmount().toString()).subtract(new BigDecimal(refCount.getPayAmount().toString())));
            payCount.setIcon("el-icon-coin");
            list.add(payCount);
            TbOrderPayCountVo cashCount = tbOrderInfoRepository.queryOrderPayCash(summaryDto.getShopId(), start, end);
            cashCount.setIcon("el-icon-circle-check");
            list.add(cashCount);
            refCount.setPayType("退款金额");
            refCount.setIcon("el-icon-money");
            list.add(refCount);

            TbOrderSalesCountByDayVo numCount = detailRepository.queryTbOrderSalesCount(Integer.valueOf(summaryDto.getShopId()), summaryDto.getStartTime(), summaryDto.getEndTime());
            TbOrderPayCountVo salesNum =new TbOrderPayCountVo("el-icon-goods","销售量","0",numCount.getSalesNum()-numCount.getRefNum());
            TbOrderPayCountVo refNum =new TbOrderPayCountVo("el-icon-goods","退单量","0",numCount.getRefNum());
            list.add(salesNum);
            list.add(refNum);
        }else {
            TbOrderSalesCountByDayVo tbOrderSalesCountByDayVo = detailRepository.queryTbOrderSalesCountByDaysummaryCount(Integer.valueOf(summaryDto.getShopId()), summaryDto.getCateId(), summaryDto.getProName(), summaryDto.getStartTime(), summaryDto.getEndTime());
            TbOrderPayCountVo zong =new TbOrderPayCountVo("el-icon-coin","总金额","1",tbOrderSalesCountByDayVo.getSalesAmount());
            TbOrderPayCountVo tuikuan =new TbOrderPayCountVo("el-icon-money","退款金额","1",tbOrderSalesCountByDayVo.getRefAmount());
            TbOrderPayCountVo xiaoliang =new TbOrderPayCountVo("el-icon-goods","销售量","0",tbOrderSalesCountByDayVo.getSalesNum());
            TbOrderPayCountVo tuidan =new TbOrderPayCountVo("el-icon-goods","退单量","0",tbOrderSalesCountByDayVo.getRefNum());
            list.add(zong);
            list.add(tuikuan);
            list.add(xiaoliang);
            list.add(tuidan);
        }
        return list;
    }

    @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 {
        Date now = new Date();
        if (shopTableSaleInfoDto.getStartTime() == null) {
            shopTableSaleInfoDto.setStartTime(cn.hutool.core.date.DateUtil.beginOfMonth(now));
        }

        if (shopTableSaleInfoDto.getEndTime() == null) {
            shopTableSaleInfoDto.setEndTime(cn.hutool.core.date.DateUtil.endOfDay(now));
        }

        // 比较开始和结束日期 相差 天数
        long betweenDay = cn.hutool.core.date.DateUtil.betweenDay(shopTableSaleInfoDto.getStartTime(), shopTableSaleInfoDto.getEndTime(), true);
        if (betweenDay > 31) {
            throw new BadRequestException("导出数据不能超过31天");
        }

        List<ExportTableStsDataDto> result = new ArrayList<>();

        for (int i = 0; i <= betweenDay; i++) {
            Date date = cn.hutool.core.date.DateUtil.offsetDay(shopTableSaleInfoDto.getStartTime(), i);
            String dateStr = cn.hutool.core.date.DateUtil.format(date, "yyyy-MM-dd");

            ExportTableStsDataDto dataDto = new ExportTableStsDataDto();
            dataDto.setDateStr(dateStr);

            Date startTime = cn.hutool.core.date.DateUtil.beginOfDay(date);
            Date endTime = cn.hutool.core.date.DateUtil.endOfDay(date);

            List<ShopTableSaleInfoVo> infoVos = selectSummaryTable(shopTableSaleInfoDto.getShopId(), startTime, endTime);

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

            List<TbOrderSalesCountByTable> countByTables = tbOrderDetailRepository.queryTbOrderSalesCountByTable(shopTableSaleInfoDto.getShopId(), startTime, endTime);

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

            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("日期", dateStr);
                    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));
                }
            }

            dataDto.setMergeCells(mergeList);
            dataDto.setData(list);

            result.add(dataDto);
        }

        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("退单额");

        FileUtils.downloadTableDataStsToExcel(result, keyList, response);
    }
}
