package com.cf.imes.module.executor.service.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.CalendarInterval;
import co.elastic.clients.elasticsearch._types.aggregations.DateHistogramAggregation;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.util.NamedValue;
import com.cf.imes.framework.common.enums.OrderStatusEnum;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderGoodsPlateRespVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderStatisticsAreaRespVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderStatisticsReqVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderStatisticsStatusRespVO;
import com.cf.imes.module.executor.controller.admin.plan.vo.OrderPlanStatisticsAreaRespVO;
import com.cf.imes.module.executor.controller.admin.plan.vo.OrderPlanStatisticsCountRespVO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateGoodDO;
import com.cf.imes.module.executor.dal.mysql.order.OrderStatisticsMapper;
import com.cf.imes.module.executor.dal.mysql.plan.PlanMapper;
import com.cf.imes.module.executor.dal.mysql.plate.OrderPlateStatisticsMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateGoodMapper;
import com.cf.imes.module.executor.enums.OrderStatisticsUnit;
import com.cf.imes.module.system.api.dict.DictDataApi;
import com.cf.imes.module.system.api.dict.dto.DictDataRespDTO;
import com.cf.imes.module.system.enums.DictTypeConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static com.cf.imes.module.executor.enums.EsIndexEnum.ORDER_OPTIMIZE_PLATE_MODEL;

/**
 * @author Gqr
 * @since 2024/8/5 16:58
 */
@Service
@Validated
@Slf4j
public class OrderStatisticsServiceImpl implements OrderStatisticsService {

    @Resource
    private OrderStatisticsMapper orderStatisticsMapper;

    @Resource
    private PlanMapper planMapper;

    @Resource
    private OrderPlateStatisticsMapper orderPlateStatisticsMapper;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private PlateGoodMapper plateGoodMapper;

    @Resource
    private ElasticsearchClient client;

    // 常用的字段key
    private static final String DATELIST_FIELD_NAME = "dateList";
    private static final String SERIES_FIELD_NAME = "series";
    private static final String ORDER_REMAIN_PLATE_MODEL_CREATE_TIME_FIELDNAME = "createTime";
    private static final String ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME = "goods_group";
    private static final String ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME = "goods_count";
    private static final String ORDER_REMAIN_PLATE_MODEL_DATE_GROUP_NAME = "date_group";
    private static final String DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH = "yyyy-M";
    private static final String DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH_DAY = "yyyy-M-d";
    private static final String ORDER_REMAIN_PLATE_MODEL_GOODS_ID_NAME = "goodsId";

    @Override
    public Integer orderCount() {
        return orderStatisticsMapper.selectOrderCount();
    }

    @Override
    public Integer orderCountToday() {
        return orderStatisticsMapper.selectOrderCountToday();
    }

    @Override
    public Integer orderCountTodayFinish() {
        return orderStatisticsMapper.selectOrderCountTodayFinish();
    }

    @Override
    public Integer orderCountProduce() {
        return orderStatisticsMapper.selectOrderCountProduce();
    }

    @Override
    public Double orderSquareProduce() {
        return orderStatisticsMapper.selectOrderSquareProduce();
    }

    @Override
    public Map<String, Object> getOrderStatusCount(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new HashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        // 查询订单状态统计数据
        List<OrderStatisticsStatusRespVO> orderStatusRespVOS = orderStatisticsMapper.selectOrderStatusCountGroupBy(reqVO);

        // 基于相同的orderDate分组
        Map<String, List<OrderStatisticsStatusRespVO>> orderDateMap = orderStatusRespVOS.stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrderStatisticsStatusRespVO::getDate, LinkedHashMap::new, Collectors.toList()));

        // 遍历订单状态所有枚举值
        List<Map<String, Object>> series = new ArrayList<>();
        for (OrderStatusEnum orderStatusEnum : OrderStatusEnum.values()) {
            Map<String, Object> seriesItem = new HashMap<>();
            int[] sumArr = new int[dateList.size()];

            // 遍历完整的日期范围
            int index = 0;
            for (String dateStr : dateList) {
                // 查找匹配的订单状态
                List<OrderStatisticsStatusRespVO> listForDate = orderDateMap.get(dateStr);
                int count = 0;
                if (listForDate != null) {
                    count = listForDate.stream()
                            .filter(respVO -> Objects.equals(orderStatusEnum.getStatus(), respVO.getOrderStatus()))
                            .mapToInt(OrderStatisticsStatusRespVO::getOrderCount)
                            .sum();
                }

                sumArr[index++] = count;
            }

            seriesItem.put("data", sumArr);
            seriesItem.put("name", orderStatusEnum.getDescription());
            series.add(seriesItem);
        }
        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：订单类型：数量数组
        resultMap.put(SERIES_FIELD_NAME, series);

        return resultMap;
    }

    @Override
    public Map<String, Object> getOrderAndPlanCountGroup(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new LinkedHashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        Map<String, List<OrderStatisticsStatusRespVO>> orderRespMap = orderStatisticsMapper.selectOrderCountGroupByOrderDate(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrderStatisticsStatusRespVO::getDate, LinkedHashMap::new, Collectors.toList()));
        Map<String, List<OrderPlanStatisticsCountRespVO>> planRespMap = planMapper.selectPlanCountGroupByCreateTime(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrderPlanStatisticsCountRespVO::getDate, LinkedHashMap::new, Collectors.toList()));

        // 类别：单量数组
        List<Map<String, Object>> series = new ArrayList<>();
        Map<String, Object> orderSeriesItem = new HashMap<>();
        Map<String, Object> planSeriesItem = new HashMap<>();
        int[] orderCountArr = new int[dateList.size()];
        int[] planCountArr = new int[dateList.size()];
        // 遍历时间跨度列表，匹配数量存入数组，没有补0存入数组
        for (int i = 0; i < dateList.size(); i++) {
            String dateStr = dateList.get(i);
            // 存入生产单数量
            Integer orderCount = Optional.ofNullable(orderRespMap.get(dateStr))
                    .map(list -> list.stream().findFirst().orElse(new OrderStatisticsStatusRespVO()))
                    .map(OrderStatisticsStatusRespVO::getOrderCount)
                    .orElse(0);
            orderCountArr[i] = orderCount;

            // 存入排单数量
            Integer planCount = Optional.ofNullable(planRespMap.get(dateStr))
                    .map(list -> list.stream().findFirst().orElse(new OrderPlanStatisticsCountRespVO()))
                    .map(OrderPlanStatisticsCountRespVO::getCount)
                    .orElse(0);
            planCountArr[i] = planCount;
        }

        orderSeriesItem.put("data", orderCountArr);
        orderSeriesItem.put("name", "生产单单量");
        planSeriesItem.put("data", planCountArr);
        planSeriesItem.put("name", "排单单量");
        series.add(orderSeriesItem);
        series.add(planSeriesItem);

        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：类别：单量数组
        resultMap.put(SERIES_FIELD_NAME, series);

        return resultMap;
    }

    @Override
    public Map<String, Object> getOrderAndPlanAreaSumGroup(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new LinkedHashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        Map<String, List<OrderStatisticsAreaRespVO>> orderRespMap = orderStatisticsMapper.selectOrderAreaGroupByOrderDate(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrderStatisticsAreaRespVO::getDate, LinkedHashMap::new, Collectors.toList()));
        Map<String, List<OrderPlanStatisticsAreaRespVO>> planRespMap = planMapper.selectPlanAreaGroupByCreateTime(reqVO).stream()
                .sorted(Comparator.naturalOrder())
                .collect(Collectors.groupingBy(OrderPlanStatisticsAreaRespVO::getDate, LinkedHashMap::new, Collectors.toList()));

        // 类别：平方数数组
        List<Map<String, Object>> series = new ArrayList<>();
        Map<String, Object> orderSeriesItem = new HashMap<>();
        Map<String, Object> planSeriesItem = new HashMap<>();
        BigDecimal[] orderAreaArr = new BigDecimal[dateList.size()];
        BigDecimal[] planAreaArr = new BigDecimal[dateList.size()];
        // 遍历时间跨度列表，匹配数量存入数组，没有补0存入数组
        for (int i = 0; i < dateList.size(); i++) {
            String dateStr = dateList.get(i);

            // 存生产单面积
            List<OrderStatisticsAreaRespVO> orderCountRespVOS = orderRespMap.get(dateStr);
            orderAreaArr[i] = orderCountRespVOS != null && !orderCountRespVOS.isEmpty() ? orderCountRespVOS.get(0).getAreaSum() : BigDecimal.ZERO;

            // 存排单面积
            List<OrderPlanStatisticsAreaRespVO> planCountRespVOS = planRespMap.get(dateStr);
            planAreaArr[i] = planCountRespVOS != null && !planCountRespVOS.isEmpty() ? planCountRespVOS.get(0).getAreaSum() : BigDecimal.ZERO;
        }

        orderSeriesItem.put("data", orderAreaArr);
        orderSeriesItem.put("name", "生产单平方数");
        planSeriesItem.put("data", planAreaArr);
        planSeriesItem.put("name", "排单平方数");
        series.add(orderSeriesItem);
        series.add(planSeriesItem);

        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：类别：平方数数组
        resultMap.put(SERIES_FIELD_NAME, series);

        return resultMap;
    }


    @Override
    public Map<String, Object> getOrderPlateCountGroup(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new LinkedHashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        // 查询时间段内数量最多的小板，列出数量前10的goods_id
        List<String> topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateCountList(reqVO).stream()
                .map(OrderGoodsPlateRespVO::getGoodsId)
                .toList();

        // 前十goods_id基于时间分组
        Map<String, List<OrderGoodsPlateRespVO>> orderGoodsPlateRespMap = new HashMap<>();
        if (CollUtil.isNotEmpty(topTenCountGoodsId)) {
            orderGoodsPlateRespMap = orderPlateStatisticsMapper.selectTopTenPlateCountListGroupByOrderDate(topTenCountGoodsId, reqVO).stream()
                    .sorted(Comparator.naturalOrder())
                    .collect(Collectors.groupingBy(OrderGoodsPlateRespVO::getOrderDate, LinkedHashMap::new, Collectors.toList()));
        }


        // 获取所有商品{goodsId:respvo}，根据top10排序
        Map<String, OrderGoodsPlateRespVO> goodsMap = new LinkedHashMap<>();
        for (String id : topTenCountGoodsId) {
            List<OrderGoodsPlateRespVO> list = orderGoodsPlateRespMap.values().stream()
                    .flatMap(List::stream)
                    .filter(vo -> vo.getGoodsId().equals(id))
                    .toList();
            if (!list.isEmpty()) {
                // goodsId相同，其他属性任取
                goodsMap.put(id, list.get(0));
            }
        }

        // 遍历所有goods_id
        List<Map<String, Object>> series = new ArrayList<>();
        for (Map.Entry<String, OrderGoodsPlateRespVO> entry : goodsMap.entrySet()) {
            Map<String, Object> seriesItem = new HashMap<>();
            int[] sumArr = new int[dateList.size()];

            // 遍历完整的日期范围
            int index = 0;
            for (String dateStr : dateList) {
                // 查找匹配的goodsId
                List<OrderGoodsPlateRespVO> orderGoodsPlateRespVOS = orderGoodsPlateRespMap.get(dateStr);
                int count = 0;
                if (orderGoodsPlateRespVOS != null) {
                    Optional<OrderGoodsPlateRespVO> matchingRespVO = orderGoodsPlateRespVOS.stream()
                            .filter(respVO -> Objects.equals(entry.getKey(), respVO.getGoodsId()))
                            .findFirst();
                    count = matchingRespVO.map(OrderGoodsPlateRespVO::getOrderCount).orElse(0);
                }
                sumArr[index++] = count;
            }

            seriesItem.put("data", sumArr);
            seriesItem.put("id", entry.getKey());
            // 材质-商品名称-颜色-纹理-宽-高-厚-品牌
            OrderGoodsPlateRespVO orderGoodsPlateRespVO = entry.getValue();
            String specification = formatGoodsName('x', stripTrailingZeros(orderGoodsPlateRespVO.getWidth()),
                    stripTrailingZeros(orderGoodsPlateRespVO.getHeight()), stripTrailingZeros(orderGoodsPlateRespVO.getThickness()));
            String goodsName = formatGoodsName('-', orderGoodsPlateRespVO.getMaterial(), orderGoodsPlateRespVO.getGoodsName(), orderGoodsPlateRespVO.getColor(), getTextureFromDict(orderGoodsPlateRespVO.getTexture()), specification, orderGoodsPlateRespVO.getBrand());
            seriesItem.put("name", goodsName);
            series.add(seriesItem);
        }

        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：大板信息：小板数量数组
        resultMap.put(SERIES_FIELD_NAME, series);
        return resultMap;
    }

    @Override
    public Map<String, Object> getOrderPlateAreaGroup(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new LinkedHashMap<>();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);

        // 查询时间段内面积最多的小板，列出前10面积的goods_id
        List<String> topTenCountGoodsId = orderPlateStatisticsMapper.selectPlateAreaList(reqVO).stream()
                .map(OrderGoodsPlateRespVO::getGoodsId)
                .toList();

        Map<String, List<OrderGoodsPlateRespVO>> orderGoodsPlateRespMap = new HashMap<>();
        if (CollUtil.isNotEmpty(topTenCountGoodsId)) {
            // 前十goods_id基于时间分组
            orderGoodsPlateRespMap = orderPlateStatisticsMapper.selectTopTenPlateAreaListGroupByOrderDate(topTenCountGoodsId, reqVO).stream()
                    .sorted(Comparator.naturalOrder())
                    .collect(Collectors.groupingBy(OrderGoodsPlateRespVO::getOrderDate, LinkedHashMap::new, Collectors.toList()));
        }


        // 获取所有商品{goodsId:respvo}，根据top10排序
        Map<String, OrderGoodsPlateRespVO> goodsMap = new LinkedHashMap<>();
        for (String id : topTenCountGoodsId) {
            List<OrderGoodsPlateRespVO> list = orderGoodsPlateRespMap.values().stream()
                    .flatMap(List::stream)
                    .filter(vo -> vo.getGoodsId().equals(id))
                    .toList();
            if (!list.isEmpty()) {
                // goodsId相同，其他属性任取
                goodsMap.put(id, list.get(0));
            }
        }

        // 遍历所有goods_id
        List<Map<String, Object>> series = new ArrayList<>();
        for (Map.Entry<String, OrderGoodsPlateRespVO> entry : goodsMap.entrySet()) {
            Map<String, Object> seriesItem = new HashMap<>();
            BigDecimal[] areaArr = new BigDecimal[dateList.size()];

            // 遍历完整的日期范围
            int index = 0;
            for (String dateStr : dateList) {
                // 查找匹配的goodsId
                List<OrderGoodsPlateRespVO> orderGoodsPlateRespVOS = orderGoodsPlateRespMap.get(dateStr);
                BigDecimal area = new BigDecimal(0);
                if (orderGoodsPlateRespVOS != null) {
                    area = orderGoodsPlateRespVOS.stream()
                            .filter(respVO -> Objects.equals(entry.getKey(), respVO.getGoodsId()))
                            .map(vo -> vo.getOrderArea().stripTrailingZeros())
                            .findFirst().orElse(new BigDecimal(0));
                }
                areaArr[index++] = area;
            }

            seriesItem.put("data", areaArr);
            seriesItem.put("id", entry.getKey());
            // 材质-商品名称-颜色-纹理-宽-高-厚-品牌
            OrderGoodsPlateRespVO orderGoodsPlateRespVO = entry.getValue();
            String specification = formatGoodsName('x', stripTrailingZeros(orderGoodsPlateRespVO.getWidth()),
                    stripTrailingZeros(orderGoodsPlateRespVO.getHeight()), stripTrailingZeros(orderGoodsPlateRespVO.getThickness()));
            String goodsName = formatGoodsName('-', orderGoodsPlateRespVO.getMaterial(), orderGoodsPlateRespVO.getGoodsName(), orderGoodsPlateRespVO.getColor(), getTextureFromDict(orderGoodsPlateRespVO.getTexture()), specification, orderGoodsPlateRespVO.getBrand());
            seriesItem.put("name", goodsName);
            series.add(seriesItem);
        }

        // x轴时间区间字符串
        resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, reqVO.getUnit())).toList());
        // 类别：大板信息：小板平方数数组
        resultMap.put(SERIES_FIELD_NAME, series);
        return resultMap;
    }

    @Override
    public Map<String, Object> getBigPlateCountGroup(OrderStatisticsReqVO reqVO) {
        Map<String, Object> resultMap = new LinkedHashMap<>();
        Integer unit = reqVO.getUnit();

        // 所有的日期集合
        List<String> dateList = getDateList(reqVO);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        SearchResponse<Map> response;
        try {
            // 查询创建时间段内，数量最多的goods_id前十
            SearchRequest searchRequest = new SearchRequest.Builder()
                    .size(0)
                    .index(ORDER_OPTIMIZE_PLATE_MODEL.getIndex())
                    .query(q ->
                            q.bool(b -> b
                                    .must(m -> m.range(m1 -> m1.field(ORDER_REMAIN_PLATE_MODEL_CREATE_TIME_FIELDNAME)
                                            .from(reqVO.getCreateTime()[0].format(dateTimeFormatter))
                                            .to(reqVO.getCreateTime()[1].format(dateTimeFormatter))))
                                    .must(m -> m.match(m2 -> m2.field("organId").query(SecurityFrameworkUtils.getUserOrganId())))))
                    .aggregations(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME,
                            agg -> agg.terms(terms -> terms.field(ORDER_REMAIN_PLATE_MODEL_GOODS_ID_NAME).size(10).order(new NamedValue<>(ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME, SortOrder.Desc)))
                                    .aggregations(ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME, sumAgg -> sumAgg.sum(sum -> sum.field("boardCount")))
                    )
                    .build();

            response = client.search(searchRequest, Map.class);

            Map<String, Aggregate> goodsCountAggMap = response.aggregations();
            Aggregate goodsCountAgg = goodsCountAggMap.get(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME);

            List<String> goodsIds = new ArrayList<>();
            // 构建map：日期：goodsId、count
            Map<String, List<OrderGoodsPlateRespVO>> goodsDateGroupMap = new HashMap<>();
            /**
             * 获取数量最大前十的goodsId列表
             */
            goodsCountAgg.sterms().buckets().array().forEach(e -> goodsIds.add(e.key().stringValue()));

            if (CollUtil.isNotEmpty(goodsIds)) {
                List<FieldValue> goodsIdFieldValueList = goodsIds.stream().map(FieldValue::of).toList();
                // 查询创建时间段内，数量最多的goods_id前十下的数据，按goods_id和日期分组
                SearchRequest dateGroupRequest = new SearchRequest.Builder()
                        .size(0)
                        .index(ORDER_OPTIMIZE_PLATE_MODEL.getIndex())
                        .query(q ->
                                q.bool(b -> b
                                        .must(m -> m.range(m1 -> m1.field(ORDER_REMAIN_PLATE_MODEL_CREATE_TIME_FIELDNAME)
                                                .from(reqVO.getCreateTime()[0].format(dateTimeFormatter))
                                                .to(reqVO.getCreateTime()[1].format(dateTimeFormatter))))
                                        .must(m -> m.match(m2 -> m2.field("organId").query(SecurityFrameworkUtils.getUserOrganId())))
                                        .must(m -> m.bool(m3 -> m3.must(t -> t.terms(gi -> gi.field(ORDER_REMAIN_PLATE_MODEL_GOODS_ID_NAME).terms(tv -> tv.value(goodsIdFieldValueList))))))
                                )
                        )
                        .aggregations(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME, agg ->
                                agg.terms(terms -> terms.field(ORDER_REMAIN_PLATE_MODEL_GOODS_ID_NAME))
                                        .aggregations(ORDER_REMAIN_PLATE_MODEL_DATE_GROUP_NAME, dateAgg -> dateAgg.dateHistogram(date -> getDateHistogram(unit, date.field(ORDER_REMAIN_PLATE_MODEL_CREATE_TIME_FIELDNAME)))
                                                .aggregations(ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME, sumAgg -> sumAgg.sum(sum -> sum.field("boardCount")))
                                        )
                        )
                        .build();
                response = client.search(dateGroupRequest, Map.class);
                Map<String, Aggregate> goodsDateCountAggMap = response.aggregations();
                Aggregate goodsDateAgg = goodsDateCountAggMap.get(ORDER_REMAIN_PLATE_MODEL_GOODS_GROUP_NAME);


                goodsDateAgg.sterms().buckets().array().forEach(goodsDateAggBucket -> {
                    // todo 目前没有发现好的es统计月周的方式，先把年月日查出来转周，后续优化
                    goodsDateAggBucket.aggregations().get(ORDER_REMAIN_PLATE_MODEL_DATE_GROUP_NAME).dateHistogram().buckets().array().forEach(dateHistogramBucket -> {
                        // 时间轴
                        String dateStr = dateToWeekMonth(dateHistogramBucket.keyAsString(), unit);
                        // 时间轴下的boardCount
                        double goodsCount = dateHistogramBucket.aggregations().get(ORDER_REMAIN_PLATE_MODEL_GOODS_COUNT_NAME).sum().value();
                        // goodsid+数量存入map，key：时间轴
                        List<OrderGoodsPlateRespVO> orderGoodsPlateRespVOS = goodsDateGroupMap.get(dateStr);
                        OrderGoodsPlateRespVO vo = OrderGoodsPlateRespVO.builder().goodsId(goodsDateAggBucket.key().stringValue()).orderDate(dateStr).orderCount((int) goodsCount).build();
                        if (ObjectUtil.isNotNull(orderGoodsPlateRespVOS)) {
                            orderGoodsPlateRespVOS.add(vo);
                        } else {
                            ArrayList<OrderGoodsPlateRespVO> goodsPlateRespVOS = new ArrayList<>();
                            goodsPlateRespVOS.add(vo);
                            goodsDateGroupMap.put(dateStr, goodsPlateRespVOS);
                        }
                    });
                });
            }

            // 遍历所有goods_id
            List<Map<String, Object>> series = new ArrayList<>();
            for (String goodsId : goodsIds) {
                Map<String, Object> seriesItem = new HashMap<>();
                int[] countArr = new int[dateList.size()];

                // 遍历完整的日期范围
                int index = 0;
                for (String dateStr : dateList) {
                    // 查找匹配的goodsId
                    List<OrderGoodsPlateRespVO> orderGoodsPlateRespVOS = goodsDateGroupMap.get(dateStr);
                    int count = 0;
                    if (orderGoodsPlateRespVOS != null) {
                        count = orderGoodsPlateRespVOS.stream()
                                .filter(respVO -> Objects.equals(goodsId, respVO.getGoodsId()))
                                .map(OrderGoodsPlateRespVO::getOrderCount)
                                .findFirst().orElse(0);
                    }
                    countArr[index++] = count;
                }

                seriesItem.put("data", countArr);
                seriesItem.put("id", goodsId);
                // 材质-商品名称-颜色-纹理-宽-高-厚-品牌
                List<PlateGoodDO> plateGoodDOList = plateGoodMapper.selectList(new LambdaQueryWrapperX<PlateGoodDO>().eq(PlateGoodDO::getGoodsId, goodsId));
                if (CollUtil.isEmpty(plateGoodDOList)) {
                    // 没有对应大板不展示
                    log.error("[getBigPlateCountGroup][统计大板数量，查询大板{} 不存在]", goodsId);
                    continue;
                }
                // 任意取一个类型
                PlateGoodDO plateGoodDO = plateGoodDOList.get(0);
                String specification = formatGoodsName('x', stripTrailingZeros(BigDecimal.valueOf(plateGoodDO.getWidth())),
                        stripTrailingZeros(BigDecimal.valueOf(plateGoodDO.getHeight())), stripTrailingZeros(BigDecimal.valueOf(plateGoodDO.getThickness())));
                String goodsName = formatGoodsName('-', plateGoodDO.getMaterial(), plateGoodDO.getGoodsName(), plateGoodDO.getColor(), getTextureFromDict(plateGoodDO.getTexture()), specification, plateGoodDO.getBrand());
                seriesItem.put("name", goodsName);
                series.add(seriesItem);
            }

            // x轴时间区间字符串
            resultMap.put(DATELIST_FIELD_NAME, dateList.stream().map(date -> generateDateRangeAxis(date, unit)).toList());
            // 类别：大板信息：大板数量数组
            resultMap.put(SERIES_FIELD_NAME, series);
        } catch (IOException e) {
            log.error("[getBigPlateCountGroup][统计大板数量异常：{}]", e.getMessage(), e);
        }
        return resultMap;
    }

    /**
     * 板材信息用-连接
     *
     * @param connChar 连接符
     * @param texts    信息内容
     * @return 为空时不带connChar
     */
    private String formatGoodsName(char connChar, String... texts) {
        StringBuilder sb = new StringBuilder();
        for (String text : texts) {
            if (StringUtils.isNotEmpty(text)) {
                sb.append(text).append(connChar);
            }
        }
        // 移除最后一个 -
        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == connChar) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


    /**
     * 根据纹路枚举获取字典中纹路描述
     *
     * @param texture
     * @return
     */
    private String getTextureFromDict(Boolean texture) {
        if (ObjectUtil.isNull(texture)) {
            return "无";
        }
        // 获取纹路描述
        DictDataRespDTO grainDTO = dictDataApi.getDictData(DictTypeConstants.PLATE_TEXTURE_TYPE, String.valueOf(texture)).getData();
        if (ObjectUtil.isNotNull(grainDTO)) {
            return Objects.equals("是", grainDTO.getLabel()) ? "有" : "无";
        } else {
            return "无";
        }
    }


    /**
     * 根据统计维度获取es分组的dateHistogram
     *
     * @return
     */
    private DateHistogramAggregation.Builder getDateHistogram(Integer unit, DateHistogramAggregation.Builder builder) {
        switch (OrderStatisticsUnit.fromValue(unit)) {
            case QUARTER:
                return builder.calendarInterval(CalendarInterval.Quarter).format("yyyy-Q");
            case MONTH:
                return builder.calendarInterval(CalendarInterval.Month).format(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH);
            case DAY, WEEK:
            default:
                return builder.calendarInterval(CalendarInterval.Day).format(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH_DAY);
        }
    }


    /**
     * 年月日转年月周
     *
     * @param dateStr
     * @return
     */
    private String dateToWeekMonth(String dateStr, Integer unit) {
        if (OrderStatisticsUnit.WEEK.getValue().equals(unit)) {
            LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH_DAY));
            // 年月
            String outDateStr = date.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH));
            // 计算从月份第一天到当前日期经过了多少周
            LocalDate monthStart = date.with(TemporalAdjusters.firstDayOfMonth());
            long weeksInMonth = ChronoUnit.WEEKS.between(monthStart, date) + 1;
            return outDateStr + "-" + weeksInMonth;
        }
        return dateStr;
    }



    /**
     * 获取日期区间格式下的所有日期字符串
     * 1、reqVO设置机构id
     * 2、计算时间跨度设置到reqVO
     * 3、返回所有日期的集合
     * @param reqVO
     * @return
     */
    private List<String> getDateList(OrderStatisticsReqVO reqVO) {
        // 计算时间跨度
        getTimeSpan(reqVO);

        // 重新计算开始时间喝结束时间
        countTimeSpan(reqVO);

        // 所有的日期集合
        return generateDateRange(reqVO);
    }

    /**
     * 获取统计的时间跨度
     * 计算起止时间：前端不传入时间就根据维度单位从当前日期计算
     *
     * @param reqVO
     */
    private void getTimeSpan(OrderStatisticsReqVO reqVO) {
        LocalDate[] createTime = reqVO.getCreateTime();
        LocalDate startTime = null;
        LocalDate endTime;
        LocalDate now = LocalDate.now();
        if (ObjectUtil.isNull(createTime) || ObjectUtil.isNull(createTime[0]) || ObjectUtil.isNull(createTime[1])) {
            endTime = now;
            switch (OrderStatisticsUnit.fromValue(reqVO.getUnit())) {
                case QUARTER:
                    // 从now往前的1年
                    startTime = now.minusYears(1);
                    break;
                case MONTH:
                    // 包含now往前的12个月
                    startTime = now.minusMonths(11);
                    break;
                case WEEK:
                    // 包含now往前的12周
                    startTime = now.minusWeeks(11);
                    break;
                case DAY:
                    // 包含now往前的15天
                    startTime = now.minusDays(14);
                    break;
                default:
                    break;
            }
            // 声明一个LocalDateTime的数组，把startTime和endTime放进去
            reqVO.setCreateTime(new LocalDate[]{startTime, endTime});
        }
    }

    /**
     * 根据传入信息重新计算时间范围
     *
     * @param reqVO
     */
    private void countTimeSpan(OrderStatisticsReqVO reqVO) {
        Integer unit = reqVO.getUnit();
        // 计算时间跨度
        getTimeSpan(reqVO);
        // 计算后的开始和结束时间
        LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);

        if (startDate.isAfter(endDate)) {
            startDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);
            endDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        }
        LocalDate first = startDate;
        LocalDate end = endDate;
        switch (OrderStatisticsUnit.fromValue(unit)) {
            case QUARTER -> {
                first = firstDayOfQuarter(startDate);
                end = lastDayOfQuarter(endDate);
            }
            case MONTH -> {
                first = startDate.with(TemporalAdjusters.firstDayOfMonth());
                end = endDate.with(TemporalAdjusters.lastDayOfMonth());
            }
            case WEEK -> {
                first = startDate.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
                end = endDate.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
            }
            default -> {
                return;
            }
        }
        reqVO.setCreateTime(new LocalDate[]{first, end});
    }

    private LocalDate firstDayOfQuarter(LocalDate date) {
        int month = date.getMonthValue();
        int quarter = (month - 1) / 3 + 1;
        int startMonth = (quarter - 1) * 3 + 1;
        return LocalDate.of(date.getYear(), startMonth, 1);
    }

    private LocalDate lastDayOfQuarter(LocalDate date) {
        int month = date.getMonthValue();
        int quarter = (month - 1) / 3 + 1;
        int endMonth = (quarter - 1) * 3 + 3;
        return LocalDate.of(date.getYear(), endMonth, 1).with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 获取日期范围内的所有格式字符串
     *
     * @param reqVO
     * @return
     */
    private List<String> generateDateRange(OrderStatisticsReqVO reqVO) {
        Integer unit = reqVO.getUnit();
        // 计算时间跨度
        getTimeSpan(reqVO);
        // 计算后的开始和结束时间
        LocalDate startDate = ObjectUtil.clone(reqVO.getCreateTime()[0]);
        LocalDate endDate = ObjectUtil.clone(reqVO.getCreateTime()[1]);

        List<String> dates = new ArrayList<>();
        while (!startDate.isAfter(endDate)) {
            String dateStr;
            switch (OrderStatisticsUnit.fromValue(unit)) {
                case QUARTER:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-Q"));
                    // 加一季度（3个月）
                    startDate = startDate.plusMonths(3);
                    break;
                case MONTH:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH));
                    // 加一月
                    startDate = startDate.plusMonths(1);
                    break;
                case WEEK:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-M-ww"));
                    // 加一周
                    startDate = startDate.plusWeeks(1);
                    break;
                case DAY:
                    dateStr = startDate.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER_PATTERN_YEAR_MONTH_DAY));
                    // 加一天
                    startDate = startDate.plusDays(1);
                    break;
                default:
                    throw new IllegalArgumentException("Unsupported unit: " + unit);
            }
            dates.add(dateStr);
        }
        return dates;
    }

    /**
     * 构建日期格式到图标横轴可用格式
     * 2024-1 -> 2024年第1季度
     * 2024-1-1 -> 2024年1月
     * ...
     * @param unit
     * @return
     */
    private String generateDateRangeAxis(String date, Integer unit) {
        OrderStatisticsUnit orderStatisticsUnit = OrderStatisticsUnit.fromValue(unit);
        StringBuilder newDateStrBuffer = new StringBuilder();
        String[] dateSplit = date.split("-");
        switch (orderStatisticsUnit) {
            case QUARTER:
                newDateStrBuffer.append("第").append(dateSplit[1]).append("季度");
                break;
            case MONTH:
                newDateStrBuffer.append(dateSplit[1]).append("月");
                break;
            case WEEK:
                newDateStrBuffer.append("第").append(dateSplit[2]).append("周");
                break;
            case DAY:
                newDateStrBuffer.append(dateSplit[2]).append("日");
                break;
            default:
        }
        return newDateStrBuffer.toString();
    }

    /**
     * 移除尾数的0，600.000 -> 600
     *
     * @param data
     * @return
     */
    private String stripTrailingZeros(BigDecimal data) {
        if (ObjectUtil.isNotNull(data)) {
            return data.stripTrailingZeros().toPlainString();
        } else {
            return "";
        }
    }

}
