package com.ruoyi.excel.wecom.helper;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.excel.wecom.domain.*;
import com.ruoyi.excel.wecom.mapper.*;
import com.ruoyi.excel.wecom.model.WecomCustomer;
import com.ruoyi.excel.wecom.model.WecomTagGroup;
import com.ruoyi.excel.wecom.service.CustomerExportService;
import com.ruoyi.excel.wecom.service.WecomContactService;
import com.ruoyi.excel.wecom.service.WecomTagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Component public class HandleAllData {
    @Autowired
    private WecomContactService wecomContactService;
    @Autowired
    private WecomTagService wecomTagService;
    @Autowired
    private CorpDepartmentMapper departmentMapper;

    @Autowired
    private CustomerExportService customerExportService;
    @Autowired
    private CorpUserMapper userMapper;
    @Autowired
    private CustomerExportDataMapper customerExportDataMapper;

    @Autowired
    private CustomerStatisticsDataMapper dataMapper;

    @Autowired
    private DepartmentStatisticsDataMapper departmentStatisticsDataMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private CorpInfoMapper corpInfoMapper;

    private List<String> finishFlag = Arrays.asList("已成交及时单9元+", "已成交非及时单9元+");
    private List<String> timelyFinishFlag = Arrays.asList("已成交及时单9元+");
    private List<String> noTimelyfinishFlag = Arrays.asList("已成交非及时单9元+");
    /**
     * 线程池配置 - 用于并行处理客户数据
     * 设置为4个线程，适应4核8G服务器环境
     */
    private final ExecutorService executorService = Executors.newFixedThreadPool(
            4,
            new ThreadFactory() {
                private final AtomicInteger threadNumber = new AtomicInteger(1);
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r, "customer-data-handler-" + threadNumber.getAndIncrement());
                    thread.setDaemon(false);
                    return thread;
                }
            }
    );

    /**
     *  抓取客户列表数据（多线程版本）
     *  注意：由于使用多线程，移除了 @Transactional 注解，事务管理在 handleData 方法中处理
     */
    public void handleAllData() throws IOException {
        List<CorpInfo> corpInfos = corpInfoMapper.selectCorpInfoList(new CorpInfo());
        corpInfos.forEach(item->{
            try {
                //根据公司信息处理
                //暂时不考虑 员工和部门变动情况下的场景 获取所有批量详情接口数
                //1.获取所有配置了客户联系功能的员工列表
                List<String> followUserList = wecomContactService.getFollowUserList(item.getCorpId());

                int batchSize = 30;
                int totalSize = followUserList.size();

                // 创建任务列表
                List<CompletableFuture<Void>> futures = new ArrayList<>();

                for (int i = 0; i < totalSize; i += batchSize) {
                    // 计算当前批次的结束位置，防止越界
                    int end = Math.min(i + batchSize, totalSize);

                    // 获取当前批次的数据
                    List<String> batch = followUserList.subList(i, end);

                    // 提交异步任务（需要传递 corpId 到子线程）
                    String finalCorpId = item.getCorpId();
                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                        try {
                            processBatch(batch,finalCorpId);
                        } catch (IOException e) {
                            throw new RuntimeException("处理批次数据失败: " + e.getMessage(), e);
                        }
                    }, executorService);

                    futures.add(future);
                }

                // 等待所有任务完成
                try {
                    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                } catch (Exception e) {
                    throw new IOException("多线程处理客户数据时发生错误: " + e.getMessage(), e);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });



    }

    /**
     * 处理单个批次的员工客户数据
     * @param batch 员工ID列表
     */
    private void processBatch(List<String> batch,String corpId) throws IOException {
        List<WecomCustomer> wecomCustomers = new ArrayList<>();
        String tmpCursor = null;

        do {
            tmpCursor = wecomContactService.batchGetCustomerDetails(corpId,batch, wecomCustomers, tmpCursor, 100);
            // 处理当前批次的客户数据
            customerExportService.handleData(corpId,wecomCustomers);
            wecomCustomers.clear();
        } while(tmpCursor != null);

        customerExportService.handleData(corpId,wecomCustomers);
    }

    /**
     * 关闭线程池（在应用关闭时调用）
     */
    public void shutdown() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 创建所有日期的流量看板数据（包含当日统计）- 优化版
     * 采用分批处理策略，控制并发数量，避免CPU持续满载
     */
    public void createAllReportData() {
        List<CorpInfo> corpInfos = corpInfoMapper.selectCorpInfoList(new CorpInfo());
        int batchSize = 10;
        
        for (CorpInfo item : corpInfos) {
            try {
                String corpId = item.getCorpId();
                List<Date> allDate = customerExportService.getAllDate(corpId);
                
                for (int i = 0; i < allDate.size(); i += batchSize) {
                    int end = Math.min(i + batchSize, allDate.size());
                    List<Date> batchDates = allDate.subList(i, end);
                    
                    List<CompletableFuture<Void>> futures = new ArrayList<>();
                    for (Date date : batchDates) {
                        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                            createReportData(corpId, date);
                        }, executorService);
                        futures.add(future);
                    }
                    
                    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                }
            } catch (Exception e) {
                throw new RuntimeException("多线程处理流量看板数据时发生错误: " + e.getMessage(), e);
            }
        }
    }

    /**
     * 创建所有部门指标数据 - 优化版
     * 采用分批处理策略，控制并发数量，避免CPU持续满载
     */
    public void createAllDepartmentReportData() {
        List<CorpInfo> corpInfos = corpInfoMapper.selectCorpInfoList(new CorpInfo());
        int batchSize = 10;
        
        for (CorpInfo item : corpInfos) {
            try {
                String corpId = item.getCorpId();
                List<Date> allDate = customerExportService.getAllDate(corpId);
                
                for (int i = 0; i < allDate.size(); i += batchSize) {
                    int end = Math.min(i + batchSize, allDate.size());
                    List<Date> batchDates = allDate.subList(i, end);
                    
                    List<CompletableFuture<Void>> futures = new ArrayList<>();
                    for (Date date : batchDates) {
                        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                            createDepartmentReportData(corpId, date);
                        }, executorService);
                        futures.add(future);
                    }
                    
                    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                }
            } catch (Exception e) {
                throw new RuntimeException("多线程处理部门报表数据时发生错误: " + e.getMessage(), e);
            }
        }
    }

    /**
     * 创建流量看板数据（包含当日统计）
     * @param date 统计日期
     */
    public  void createReportData(String corpId,Date date) {
        // 先删除当天已存在的数据，避免重复
        LambdaQueryWrapper<CustomerStatisticsData> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(CustomerStatisticsData::getCorpId, corpId)
                     .eq(CustomerStatisticsData::getCurDate, date);
        dataMapper.delete(deleteWrapper);

        // 重新计算并插入当天数据
        List<CustomerStatisticsData> oneDateData = calculateStatistics(corpId,date);
        oneDateData.forEach(item->{
            dataMapper.insert(item);
        });
    }

    /**初始化基础数据 如果需要同步 需要删除老数据数据*/
    public boolean initData() throws IOException {

        List<CorpInfo> corpInfos = corpInfoMapper.selectCorpInfoList(new CorpInfo());
        corpInfos.forEach(oneCorp-> {
            try {
                List<CorpDepartment> departmentList;
                Map<Long, String> cacheDepartMap = new HashMap<>();
                Map<Long, Long> parentCacheMap = new HashMap<>();
                String corpId = oneCorp.getCorpId();
                try {
                    //存入部门id
                    departmentList = wecomContactService.getDepartmentList(corpId,null);
                    //循环获取部门详情数据
                    for (CorpDepartment item : departmentList) {
                        String departmentDetail = null;
                        departmentDetail = wecomContactService.getDepartmentDetail(corpId,item.getId());

                        item.setName(departmentDetail);
                        item.setCorpId(corpId); // 设置企业ID
                        cacheDepartMap.put(item.getId(), departmentDetail);
                        parentCacheMap.put(item.getId(), item.getParentid());
                        //保存部门数据（支持重复调用：存在则更新，不存在则插入）
                        CorpDepartment existingDept = departmentMapper.selectById(item.getId());
                        if (existingDept != null) {
                            departmentMapper.updateById(item);
                        } else {
                            departmentMapper.insert(item);
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException("存储部门数据失败！");
                }

                try {
                    //根据部门id循环获取下面的员工信息
                    departmentList.forEach(item -> {
                        try {
                            List<CorpUser> departmentMemberList = wecomContactService.getDepartmentMemberList(corpId,item.getId(), null, null);
                            departmentMemberList.forEach(oneUser -> {
                                oneUser.setDepartId(item.getId());
                                oneUser.setDepartmentName(getDepartmentFullPath(item.getId(), cacheDepartMap, parentCacheMap));
                                oneUser.setCorpId(corpId); // 设置企业ID
                                //保存用户数据（支持重复调用：存在则更新，不存在则插入）
                                CorpUser existingUser = userMapper.selectByUserId(oneUser.getUserid());
                                if (existingUser != null) {
                                    userMapper.updateById(oneUser);
                                } else {
                                    userMapper.insert(oneUser);
                                }
                            });
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
                } catch (Exception e) {
                    throw new RuntimeException("存储员工数据失败！");
                }

                try {
                    //查询所有标签信息 存储标签信息
                    List<WecomTagGroup> tagGroupList = wecomContactService.getCorpTagList(corpId);

                    // 同步标签库到数据库
                    wecomTagService.syncCorpTagList(tagGroupList,corpId);
                } catch (Exception e) {
                    throw new RuntimeException("存储标签数据失败！");
                }

                customerExportService.refreshCache();

            }catch (Exception e) {
                throw new RuntimeException("初始化数据异常");
            }
        });
        return true;
    }

    /**
     * 创建部门报表数据（包含当日统计）
     * @param date 统计日期
     */
    public void createDepartmentReportData(String corpId,Date date) {
        // 先删除当天已存在的数据，避免重复
        LambdaQueryWrapper<DepartmentStatisticsData> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(DepartmentStatisticsData::getCorpId, corpId)
                     .eq(DepartmentStatisticsData::getStatDate, date);
        departmentStatisticsDataMapper.delete(deleteWrapper);

        // 重新计算并插入当天数据
        List<DepartmentStatisticsData> oneDateData = calculateDepartmentStatistics(corpId,date);
        oneDateData.forEach(item -> {
            departmentStatisticsDataMapper.insert(item);
        });
    }


    /**===================================以下为私有方法============================================*/
    /**
     * 递归获取部门完整路径
     * @param departId 部门id
     * @param cacheDepartMap 部门id对应部门名称的缓存
     * @param parentCacheMap 部门id对应上级部门id的缓存
     * @return 完整部门路径，用"/"分隔，例如：公司/技术部/研发组
     */
    private String getDepartmentFullPath(Long departId, Map<Long, String> cacheDepartMap, Map<Long, Long> parentCacheMap) {
        // 如果部门id为空或不存在，返回空字符串
        if (departId == null || !cacheDepartMap.containsKey(departId)) {
            return "";
        }

        // 获取当前部门名称
        String currentDepartName = cacheDepartMap.get(departId);

        // 获取父部门id
        Long parentId = parentCacheMap.get(departId);

        // 如果没有父部门或父部门id为0（根部门），返回当前部门名称
        if (parentId == null || parentId == 0) {
            return currentDepartName;
        }

        // 递归获取父部门路径
        String parentPath = getDepartmentFullPath(parentId, cacheDepartMap, parentCacheMap);

        // 拼接父部门路径和当前部门名称
        if (parentPath.isEmpty()) {
            return currentDepartName;
        } else {
            return parentPath + "/" + currentDepartName;
        }
    }



    /**
     * 统计客户数据（支持日期参数）
     * @param targetDate 目标日期，格式：yyyy-MM-dd，如 "2026-01-03" 表示1月3日
     * @return 统计结果列表
     */
    /**
     * 计算统计数据 - 优化版
     * SQL层面过滤日期，减少数据传输和Java层过滤开销
     * @param date 目标日期 (格式: yyyy-MM-dd)
     * @return 统计结果列表
     */
    private List<CustomerStatisticsData> calculateStatistics(String corpId,Date date) {
        // 1. 初始化累加器
        StatisticsAccumulator accumulator = new StatisticsAccumulator();

        // 2. 分页查询并累加统计（SQL层面直接过滤日期）
        int pageSize = 1000;
        int pageNum = 1;
        LambdaQueryWrapper<CustomerExportData> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustomerExportData::getCorpId, corpId)
               .eq(CustomerExportData::getAddDate, date);
        
        while (true) {
            Page<CustomerExportData> page = new Page<>(pageNum, pageSize);
            Page<CustomerExportData> pageData = customerExportDataMapper.selectPage(page, wrapper);

            for (CustomerExportData data : pageData.getRecords()) {
                processDataRecord(data, date, accumulator);
            }

            if (!pageData.hasNext()) {
                break;
            }
            pageNum++;
        }

        // 3. 从累加器生成最终结果
        return generateStatisticsResults(corpId,date,accumulator);
    }


    /**
     * 计算部门维度的统计数据（当日）- 优化版
     * SQL层面过滤日期，减少数据传输和Java层过滤开销
     * @param targetDate 目标日期 (格式: yyyy-MM-dd)
     * @return 部门统计结果列表
     */
    private List<DepartmentStatisticsData> calculateDepartmentStatistics(String corpId,Date targetDate) {
        // 1. 初始化部门累加器
        DepartmentStatisticsAccumulator accumulator = new DepartmentStatisticsAccumulator();

        // 2. 分页查询并累加统计（SQL层面直接过滤日期）
        int pageSize = 1000;
        int pageNum = 1;
        LambdaQueryWrapper<CustomerExportData> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CustomerExportData::getCorpId, corpId)
                .and(w -> w.eq(CustomerExportData::getAddDate, targetDate)
                        .or()
                        .eq(CustomerExportData::getFinishDate, targetDate));

        ;
        
        while (true) {
            Page<CustomerExportData> page = new Page<>(pageNum, pageSize);
            Page<CustomerExportData> pageData = customerExportDataMapper.selectPage(page, wrapper);

            for (CustomerExportData data : pageData.getRecords()) {
                // 获取部门路径
                String departmentPath = data.getAddUserDepartment();
                if (departmentPath == null || departmentPath.trim().isEmpty()) {
                    continue;
                }

                // 先计算所有条件，避免重复判断
                boolean isQValueMatch = matchesQValue(data, targetDate);
                boolean isSourceMatch = matchesSource(data);
                boolean isTimelyOrder = isTimelyOrder(data);
                boolean isNoTimelyOrder = isNoTimelyOrder(data);
                String customerAttr = data.getTagGroup6();
                boolean isParent = customerAttr != null && !customerAttr.trim().isEmpty() && customerAttr.contains("家长");
                boolean isStudent = customerAttr != null && !customerAttr.trim().isEmpty() && customerAttr.contains("学生");

                // 提取各级路径
                String[] pathParts = departmentPath.split("/");

                // 构建各级路径并累加统计（只遍历一次，条件已预先计算）
                StringBuilder pathBuilder = new StringBuilder();
                for (int i = 0; i < pathParts.length; i++) {
                    if (i > 0) {
                        pathBuilder.append("/");
                    }
                    pathBuilder.append(pathParts[i]);
                    String currentPath = pathBuilder.toString();
                    DepartmentStatisticsAccumulator.DepartmentStats stats = accumulator.getDepartmentStats(currentPath);

                    // 累加统计（SQL已过滤日期，所有数据都是目标日期的）
                    if (isQValueMatch) {
                        stats.setTotalOrderCount(stats.getTotalOrderCount() + 1);
                        if (isTimelyOrder) {
                            stats.setTimelyOrderCount(stats.getTimelyOrderCount() + 1);
                        } else if(isNoTimelyOrder){
                            stats.setNonTimelyOrderCount(stats.getNonTimelyOrderCount() + 1);
                        }
                    }

                    if (isSourceMatch && data.getAddDate().compareTo(targetDate) == 0) {
                        stats.setTotalAcceptCount(stats.getTotalAcceptCount() + 1);
                        if (isParent) {
                            stats.setParentDailyCount(stats.getParentDailyCount() + 1);
                            if (isQValueMatch && isTimelyOrder) {
                                stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
                            }
                        } else if (isStudent) {
                            stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
                            if (isQValueMatch && isTimelyOrder) {
                                stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
                            }
                        }
                    } else if(data.getAddDate().compareTo(targetDate) == 0){
                        stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
                    }
                }
            }

            // 检查是否还有下一页
            if (!pageData.hasNext()) {
                break;
            }
            pageNum++;
        }

        //
        // 3. 从累加器生成最终结果
        return generateDepartmentStatisticsResults(corpId,accumulator, targetDate);
    }

    /**
     * 组名到字段名的映射
     */
    private static final Map<String, String> GROUP_FIELD_MAP = new LinkedHashMap<>();
    static {
        GROUP_FIELD_MAP.put("N组", "tagGroup1");
        GROUP_FIELD_MAP.put("O组", "tagGroup2");
        GROUP_FIELD_MAP.put("P组", "tagGroup3");
        GROUP_FIELD_MAP.put("W组", "tagGroup10");
        GROUP_FIELD_MAP.put("X组", "tagGroup11");
        GROUP_FIELD_MAP.put("Y组", "tagGroup12");
        GROUP_FIELD_MAP.put("Z组", "tagGroup13");
        GROUP_FIELD_MAP.put("AA组", "tagGroup14");
        GROUP_FIELD_MAP.put("AC组", "tagGroup16");
        GROUP_FIELD_MAP.put("AD组", "tagGroup17");
        GROUP_FIELD_MAP.put("AE组", "tagGroup18");
    }

    private static final Map<String, String> GROUP_ATTR_MAP = new LinkedHashMap<>();
    static {
        GROUP_ATTR_MAP.put("N组", "tag_group1");
        GROUP_ATTR_MAP.put("O组", "tag_group2");
        GROUP_ATTR_MAP.put("P组", "tag_group3");
        GROUP_ATTR_MAP.put("W组", "tag_group10");
        GROUP_ATTR_MAP.put("X组", "tag_group11");
        GROUP_ATTR_MAP.put("Y组", "tag_group12");
        GROUP_ATTR_MAP.put("Z组", "tag_group13");
        GROUP_ATTR_MAP.put("AA组", "tag_group14");
        GROUP_ATTR_MAP.put("AC组", "tag_group16");
        GROUP_ATTR_MAP.put("AD组", "tag_group17");
        GROUP_ATTR_MAP.put("AE组", "tag_group18");
    }

    private static final String UNGROUPED_NAME = "未分组";

    /**
     * 字段反射缓存
     */
    private static final Map<String, java.lang.reflect.Field> FIELD_CACHE = new java.util.concurrent.ConcurrentHashMap<>();

    /**
     * 检查数据是否匹配日期和来源条件
     */
    private boolean matchesDate(CustomerExportData data, Date date) {
        // 条件1: 日期匹配
        if (data.getAddDate() != null && date != null) {
            if (date.compareTo(data.getAddDate()) != 0) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    private boolean matchesSource(CustomerExportData data) {
        if(data.getSource() == null) {
            return true;
        }
        // 条件: 排除"由管理员XXX分配"
        if (data.getSource().contains("管理员") &&
                data.getSource().contains("分配")) {
            return false;
        }

        return true;
    }

    private boolean matchesQValue(CustomerExportData data,Date curDate) {
        Date finishDate = data.getFinishDate();
        if (finishDate == null) {
            return false;
        }

        try {
            Calendar orderCal = Calendar.getInstance();
            orderCal.setTime(finishDate);
            orderCal.set(Calendar.HOUR_OF_DAY, 0);
            orderCal.set(Calendar.MINUTE, 0);
            orderCal.set(Calendar.SECOND, 0);
            orderCal.set(Calendar.MILLISECOND, 0);

            Calendar targetCal = Calendar.getInstance();
            targetCal.setTime(curDate);
            targetCal.set(Calendar.HOUR_OF_DAY, 0);
            targetCal.set(Calendar.MINUTE, 0);
            targetCal.set(Calendar.SECOND, 0);
            targetCal.set(Calendar.MILLISECOND, 0);

            return orderCal.getTimeInMillis() == targetCal.getTimeInMillis();

        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 检查是否是成单状态
     */
    private boolean isOrderCompleted(CustomerExportData data) {
        String orderStatus = data.getTagGroup7(); // T列：成交状态
        if (orderStatus == null || orderStatus.trim().isEmpty()) {
            return false;
        }
        // 校验成交状态
        return orderStatus.contains("已成交及时单9元+") || orderStatus.contains("已成交非及时单9元+");
    }

    private boolean isTimelyOrder(CustomerExportData data) {
        String orderStatus = data.getTagGroup7();
        if (orderStatus == null || orderStatus.trim().isEmpty()) {
            return false;
        }
        return orderStatus.equals("已成交及时单9元+");
    }
    private boolean isNoTimelyOrder(CustomerExportData data) {
        String orderStatus = data.getTagGroup7();
        if (orderStatus == null || orderStatus.trim().isEmpty()) {
            return false;
        }
        return orderStatus.equals("已成交非及时单9元+");
    }
    /**
     * 处理单条数据记录，累加到所有相关组的统计中
     */
    private void processDataRecord(CustomerExportData data, Date date, StatisticsAccumulator accumulator) {
        boolean hasGroup = false;
        
        // 遍历所有组
        for (Map.Entry<String, String> entry : GROUP_FIELD_MAP.entrySet()) {
            String groupName = entry.getKey();
            String fieldName = entry.getValue();

            // 获取该组的标签值
            String tagValue = getFieldValue(data, fieldName);

            // 如果该组标签为空，跳过
            if (tagValue == null || tagValue.trim().isEmpty()) {
                continue;
            }
            
            hasGroup = true;

            // 获取该组的统计器
            StatisticsAccumulator.GroupStatistics stats = accumulator.getGroupStats(groupName);

            // 累加各项统计指标
            accumulateGroupStatistics(data, date, stats);
        }
        
        // 如果不属于任何组，统计到"未分组"
        if (!hasGroup) {
            StatisticsAccumulator.GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME);
            accumulateGroupStatistics(data, date, ungroupedStats);
        }
    }

    /**
     * 使用反射获取字段值（带缓存）
     */
    private String getFieldValue(CustomerExportData data, String fieldName) {
        try {
            java.lang.reflect.Field field = FIELD_CACHE.computeIfAbsent(fieldName, fn -> {
                try {
                    java.lang.reflect.Field f = CustomerExportData.class.getDeclaredField(fn);
                    f.setAccessible(true);
                    return f;
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                }
            });

            Object value = field.get(data);
            return value == null ? "" : value.toString();
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 累加单条数据的统计指标
     */
    private void accumulateGroupStatistics(CustomerExportData data, Date date, StatisticsAccumulator.GroupStatistics stats) {
        if(matchesQValue(data,date)) {
            stats.setOrderCount(stats.getOrderCount() + 1);
            String orderStatus = data.getTagGroup7();
            if (orderStatus != null) {
                if (orderStatus.equals("已成交及时单9元+")) {
                    stats.setTimelyOrderCount(stats.getTimelyOrderCount() + 1);
                } else if (orderStatus.equals("已成交非及时单9元+")) {
                    stats.setNonTimelyOrderCount(stats.getNonTimelyOrderCount() + 1);
                }
            }
        }

        // 1. 成单数和及时单/非及时单
        //来源筛选
        if(!matchesSource(data) || !matchesDate(data,date)) {
            return;
        }
        // 2. 进粉数
        stats.setCustomerCount(stats.getCustomerCount() + 1);

        // 3. 客户属性统计
        String customerAttr = data.getTagGroup6();
        if (customerAttr != null && !customerAttr.trim().isEmpty()) {
            stats.setTotalCustomerAttr(stats.getTotalCustomerAttr() + 1);
            if (customerAttr.contains("家长")) {
                stats.setParentCount(stats.getParentCount() + 1);
                //todo 存在订单未完成 但是有标签的场景
                stats.setParentOrderCount(stats.getParentOrderCount() + 1);

                // 新增：出单率统计（当日）
                stats.setParentDailyCount(stats.getParentDailyCount() + 1);
                if (matchesQValue(data, date) && isTimelyOrder(data)) {
                    stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
                }

            } else if (customerAttr.contains("学生")) {
                stats.setStudentCount(stats.getStudentCount() + 1);

                stats.setStudentOrderCount(stats.getStudentOrderCount() + 1);

                // 新增：N组学生出单率统计（当日）
                stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
                if (matchesQValue(data, date) && isTimelyOrder(data)) {
                    stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
                }
            }  else if (customerAttr.contains("老师")) {
                stats.setTeacherCount(stats.getTeacherCount() + 1);
                stats.setTeacherOrderCount(stats.getTeacherOrderCount() + 1);

                // 新增：N组老师出单率统计（当日）
                stats.setTeacherDailyCount(stats.getTeacherDailyCount() + 1);
                if (matchesQValue(data, date) && isTimelyOrder(data)) {
                    stats.setTeacherDailyOrderCount(stats.getTeacherDailyOrderCount() + 1);
                }
            } else {
                stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1);
                stats.setUnkownOrderCount(stats.getUnkownOrderCount() + 1);

                // 新增：N组未知出单率统计（当日）
                stats.setUnkownDailyCount(stats.getUnkownDailyCount() + 1);
                if (matchesQValue(data, date) && isTimelyOrder(data)) {
                    stats.setUnkownDailyOrderCount(stats.getUnkownDailyOrderCount() + 1);
                }
            }
        }

        // 4. 意向度统计
        String intention = data.getTagGroup15();
        if (intention != null && !intention.trim().isEmpty() && !"空白".equals(intention)) {
            stats.setTotalIntention(stats.getTotalIntention() + 1);

            if (intention.contains("主动报价")) {
                stats.setActiveQuoteCount(stats.getActiveQuoteCount() + 1);
            } else if (intention.contains("被动报价")) {
                stats.setPassiveQuoteCount(stats.getPassiveQuoteCount() + 1);
            } else if (intention.contains("未开口")) {
                stats.setNoQuoteCount(stats.getNoQuoteCount() + 1);
            } else if (intention.contains("已删除")) {
                stats.setDeletedQuoteCount(stats.getDeletedQuoteCount() + 1);
            }
        }

        // 5. 年级统计
        String grade = data.getTagGroup5();
        if (grade != null && !grade.trim().isEmpty() && !"空白".equals(grade)) {
            stats.setTotalGrade(stats.getTotalGrade() + 1);

            if (isPrimarySchool(grade)) {
                stats.setPrimaryCount(stats.getPrimaryCount() + 1);
            } else if (isMiddleSchool(grade)) {
                stats.setMiddleCount(stats.getMiddleCount() + 1);
            } else if (isHighSchool(grade)) {
                stats.setHighCount(stats.getHighCount() + 1);
            }
        }
    }


    /**
     * 判断是否为小学
     */
    private boolean isPrimarySchool(String grade) {
        return grade.contains("小学") || grade.contains("一年级") || grade.contains("二年级") ||
               grade.contains("三年级") || grade.contains("四年级") || grade.contains("五年级") ||
               grade.contains("六年级");
    }

    /**
     * 判断是否为初中
     */
    private boolean isMiddleSchool(String grade) {
        return grade.contains("初中") || grade.contains("初一") ||
               grade.contains("初二") || grade.contains("初三");
    }

    /**
     * 判断是否为高中
     */
    private boolean isHighSchool(String grade) {
        return grade.contains("高中") || grade.contains("高一") ||
               grade.contains("高二") || grade.contains("高三");
    }

    /**
     * 从累加器生成最终统计结果
     * 修复：遍历所有预定义的组，确保"有成单但无进粉"的组也被统计
     */
    private List<CustomerStatisticsData> generateStatisticsResults(String corpId,Date curDate,StatisticsAccumulator accumulator) {
        // 使用 Map 来存储每个指标对应的 CustomerStatisticsData
        // key: 指标名称（不带组名前缀），value: CustomerStatisticsData 对象
        Map<String, CustomerStatisticsData> indicatorMap = new LinkedHashMap<>();
        //设置一个默认排序
        int sortNo = 0;
        // 为每个组生成统计指标 - 遍历所有预定义的组，确保有成单但无进粉的组也被统计
        for (Map.Entry<String, String> groupEntry : GROUP_ATTR_MAP.entrySet()) {
            String groupName = groupEntry.getKey();
            String attr = groupEntry.getValue();
            
            // 获取或创建该组的统计器
            StatisticsAccumulator.GroupStatistics stats = accumulator.getGroupStats(groupName);
            
            // 成单数需要从历史数据中获取成交日期 = date的数据
            Long finishCount = customerExportDataMapper.selectByFinishDate(corpId, curDate, attr, finishFlag);
            
            // 只有当有成单数或进粉数时才生成记录
            if (finishCount > 0 || stats.getCustomerCount() > 0) {
                // 21-23. 成本相关（需要手工填写）
                setIndicatorValue(corpId,indicatorMap,curDate, "总成本（当日）", groupName, "需手工填写",(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "单条成本（当日）", groupName, "需手工填写",(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "成单成本（当日）", groupName, "需手工填写",(10*sortNo++));

                // 1. 成单数
                setIndicatorValue(corpId,indicatorMap,curDate, "成单数（当日）", groupName, String.valueOf(finishCount),(10*sortNo++));

                // 2. 进粉数
                setIndicatorValue(corpId,indicatorMap,curDate, "进粉数（当日）", groupName, String.valueOf(stats.getCustomerCount()),(10*sortNo++));

                // 3. 转化率 = 成单数 / 进粉数
                String conversionRate = calculateRate(finishCount.intValue(), stats.getCustomerCount());
                setIndicatorValue(corpId,indicatorMap,curDate, "转化率(当日)", groupName, conversionRate,(10*sortNo++));

                // 4. 及时单占比 = 及时单数 / 成单数（当日）
                Long timelyCount = customerExportDataMapper.selectTimelyOrderCount(corpId, curDate, attr, timelyFinishFlag);
                String timelyRate = calculateRate(timelyCount.intValue(), finishCount.intValue());
                setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", groupName, String.valueOf(timelyCount),(10*sortNo++),true);

                // 5. 非及时单占比 = 非及时单数 / 成单数（当日）
                Long nonTimelyCount = customerExportDataMapper.selectNonTimelyOrderCount(corpId, curDate, attr, noTimelyfinishFlag);
                String nonTimelyRate = calculateRate(nonTimelyCount.intValue(), finishCount.intValue());
                setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", groupName, String.valueOf(nonTimelyCount),(10*sortNo++),true);

                // 6. 客户属性数量
                setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量（当日）", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++));

                // 7. 家长占比
                String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr());
                setIndicatorValue(corpId,indicatorMap,curDate, "家长占比（当日）", groupName, parentRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "家长数量（当日）", groupName, String.valueOf(stats.getParentCount()),(10*sortNo++),true);

                // 8. 学生占比
                String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr());
                setIndicatorValue(corpId,indicatorMap,curDate, "学生占比（当日）", groupName, studentRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "学生数量（当日）", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true);

                // 8. 老师占比
                String teacherRate = calculateRate(stats.getTeacherCount(), stats.getTotalCustomerAttr());
                setIndicatorValue(corpId,indicatorMap,curDate, "老师占比（当日）", groupName, teacherRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "老师数量（当日）", groupName, String.valueOf(stats.getTeacherCount()),(10*sortNo++),true);

                // 9. 未知占比
                String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr());
                setIndicatorValue(corpId,indicatorMap,curDate, "未知占比（当日）", groupName, unknownRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "未知数量（当日）", groupName, String.valueOf(stats.getUnknownAttrCount()),(10*sortNo++),true);

                // 10. 意向度数量
                setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量（当日）", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++));

                // 11. 主动报价占比
                String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention());
                setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比（当日）", groupName, activeQuoteRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量（当日）", groupName, String.valueOf(stats.getActiveQuoteCount()),(10*sortNo++),true);

                // 12. 被动报价占比
                String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention());
                setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比（当日）", groupName, passiveQuoteRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量（当日）", groupName, String.valueOf(stats.getPassiveQuoteCount()),(10*sortNo++),true);

                // 13. 未开口报价占比
                String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention());
                setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比（当日）", groupName, noQuoteRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量（当日）", groupName, String.valueOf(stats.getNoQuoteCount()),(10*sortNo++),true);

                // 14. 已删除报价占比
                String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention());
                setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比（当日）", groupName, deletedQuoteRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量（当日）", groupName, String.valueOf(stats.getDeletedQuoteCount()),(10*sortNo++),true);

                // 15. 年级数量
                setIndicatorValue(corpId,indicatorMap,curDate, "年级数量（当日）", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++));

                // 16. 小学占比
                String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade());
                setIndicatorValue(corpId,indicatorMap,curDate, "小学占比（当日）", groupName, primaryRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "小学数量（当日）", groupName, String.valueOf(stats.getPrimaryCount()),(10*sortNo++),true);

                // 17. 初中占比
                String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade());
                setIndicatorValue(corpId,indicatorMap,curDate, "初中占比（当日）", groupName, middleRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "初中数量（当日）", groupName, String.valueOf(stats.getMiddleCount()),(10*sortNo++),true);

                // 18. 高中占比
                String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade());
                setIndicatorValue(corpId,indicatorMap,curDate, "高中占比（当日）", groupName, highRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "高中数量（当日）", groupName, String.valueOf(stats.getHighCount()),(10*sortNo++),true);

                // 19. 家长出单占比
                String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount());
                setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比（当日）", groupName, parentOrderRate,(10*sortNo++),true);
                setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量（当日）", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true);

                // 20. 学生出单占比
                String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount());
                setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比（当日）", groupName, studentOrderRate,(10*sortNo++),true);
                setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量（当日）", groupName, String.valueOf(stats.getStudentOrderCount()),(10*sortNo++),true);

                // 21. 家长出单率（当日）
                String parentDailyOrderRate = calculateRate(stats.getParentDailyOrderCount(), stats.getParentDailyCount());
                setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率（当日）", groupName, parentDailyOrderRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量（当日）", groupName, String.valueOf(stats.getParentDailyOrderCount()),(10*sortNo++),true);

                // 22. 学生出单率（当日）
                String studentDailyOrderRate = calculateRate(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount());
                setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率（当日）", groupName, studentDailyOrderRate,(10*sortNo++));
                setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量（当日）", groupName, String.valueOf(stats.getStudentDailyOrderCount()),(10*sortNo++),true);
            }
        }

        // 处理"未分组"数据
        StatisticsAccumulator.GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME);
        Long ungroupedFinishCount = customerExportDataMapper.selectUngroupedFinishCount(corpId, curDate, finishFlag);
        
        if (ungroupedFinishCount > 0 || ungroupedStats.getCustomerCount() > 0) {
            // 21-23. 成本相关（需要手工填写）
            setIndicatorValue(corpId,indicatorMap,curDate, "总成本（当日）", UNGROUPED_NAME, "需手工填写",(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "单条成本（当日）", UNGROUPED_NAME, "需手工填写",(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "成单成本（当日）", UNGROUPED_NAME, "需手工填写",(10*sortNo++));

            // 1. 成单数
            setIndicatorValue(corpId,indicatorMap,curDate, "成单数（当日）", UNGROUPED_NAME, String.valueOf(ungroupedFinishCount),(10*sortNo++));

            // 2. 进粉数
            setIndicatorValue(corpId,indicatorMap,curDate, "进粉数（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getCustomerCount()),(10*sortNo++));

            // 3. 转化率
            String conversionRate = calculateRate(ungroupedFinishCount.intValue(), ungroupedStats.getCustomerCount());
            setIndicatorValue(corpId,indicatorMap,curDate, "转化率(当日)", UNGROUPED_NAME, conversionRate,(10*sortNo++));

            // 4. 及时单占比
            Long ungroupedTimelyCount = customerExportDataMapper.selectUngroupedTimelyOrderCount(corpId, curDate, timelyFinishFlag);
            String timelyRate = calculateRate(ungroupedTimelyCount.intValue(), ungroupedFinishCount.intValue());
            setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", UNGROUPED_NAME, timelyRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedTimelyCount),(10*sortNo++),true);

            // 5. 非及时单占比
            Long ungroupedNonTimelyCount = customerExportDataMapper.selectUngroupedNonTimelyOrderCount(corpId, curDate, noTimelyfinishFlag);
            String nonTimelyRate = calculateRate(ungroupedNonTimelyCount.intValue(), ungroupedFinishCount.intValue());
            setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", UNGROUPED_NAME, nonTimelyRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedNonTimelyCount),(10*sortNo++),true);

            // 6-22 其他指标（未分组记录的属性统计）
            setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalCustomerAttr()),(10*sortNo++));
            
            String parentRate = calculateRate(ungroupedStats.getParentCount(), ungroupedStats.getTotalCustomerAttr());
            setIndicatorValue(corpId,indicatorMap,curDate, "家长占比（当日）", UNGROUPED_NAME, parentRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "家长数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentCount()),(10*sortNo++),true);

            String studentRate = calculateRate(ungroupedStats.getStudentCount(), ungroupedStats.getTotalCustomerAttr());
            setIndicatorValue(corpId,indicatorMap,curDate, "学生占比（当日）", UNGROUPED_NAME, studentRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "学生数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentCount()),(10*sortNo++),true);

            String teacherRate = calculateRate(ungroupedStats.getTeacherCount(), ungroupedStats.getTotalCustomerAttr());
            setIndicatorValue(corpId,indicatorMap,curDate, "老师占比（当日）", UNGROUPED_NAME, teacherRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "老师数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTeacherCount()),(10*sortNo++),true);

            String unknownRate = calculateRate(ungroupedStats.getUnknownAttrCount(), ungroupedStats.getTotalCustomerAttr());
            setIndicatorValue(corpId,indicatorMap,curDate, "未知占比（当日）", UNGROUPED_NAME, unknownRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "未知数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getUnknownAttrCount()),(10*sortNo++),true);

            setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalIntention()),(10*sortNo++));

            String activeQuoteRate = calculateRate(ungroupedStats.getActiveQuoteCount(), ungroupedStats.getTotalIntention());
            setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比（当日）", UNGROUPED_NAME, activeQuoteRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getActiveQuoteCount()),(10*sortNo++),true);

            String passiveQuoteRate = calculateRate(ungroupedStats.getPassiveQuoteCount(), ungroupedStats.getTotalIntention());
            setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比（当日）", UNGROUPED_NAME, passiveQuoteRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getPassiveQuoteCount()),(10*sortNo++),true);

            String noQuoteRate = calculateRate(ungroupedStats.getNoQuoteCount(), ungroupedStats.getTotalIntention());
            setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比（当日）", UNGROUPED_NAME, noQuoteRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getNoQuoteCount()),(10*sortNo++),true);

            String deletedQuoteRate = calculateRate(ungroupedStats.getDeletedQuoteCount(), ungroupedStats.getTotalIntention());
            setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比（当日）", UNGROUPED_NAME, deletedQuoteRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getDeletedQuoteCount()),(10*sortNo++),true);

            setIndicatorValue(corpId,indicatorMap,curDate, "年级数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalGrade()),(10*sortNo++));

            String primaryRate = calculateRate(ungroupedStats.getPrimaryCount(), ungroupedStats.getTotalGrade());
            setIndicatorValue(corpId,indicatorMap,curDate, "小学占比（当日）", UNGROUPED_NAME, primaryRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "小学数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getPrimaryCount()),(10*sortNo++),true);

            String middleRate = calculateRate(ungroupedStats.getMiddleCount(), ungroupedStats.getTotalGrade());
            setIndicatorValue(corpId,indicatorMap,curDate, "初中占比（当日）", UNGROUPED_NAME, middleRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "初中数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getMiddleCount()),(10*sortNo++),true);

            String highRate = calculateRate(ungroupedStats.getHighCount(), ungroupedStats.getTotalGrade());
            setIndicatorValue(corpId,indicatorMap,curDate, "高中占比（当日）", UNGROUPED_NAME, highRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "高中数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getHighCount()),(10*sortNo++),true);

            String parentOrderRate = calculateRate(ungroupedStats.getParentOrderCount(), ungroupedStats.getParentCount());
            setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比（当日）", UNGROUPED_NAME, parentOrderRate,(10*sortNo++),true);
            setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentOrderCount()),(10*sortNo++),true);

            String studentOrderRate = calculateRate(ungroupedStats.getStudentOrderCount(), ungroupedStats.getStudentCount());
            setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比（当日）", UNGROUPED_NAME, studentOrderRate,(10*sortNo++),true);
            setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentOrderCount()),(10*sortNo++),true);

            String parentDailyOrderRate = calculateRate(ungroupedStats.getParentDailyOrderCount(), ungroupedStats.getParentDailyCount());
            setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率（当日）", UNGROUPED_NAME, parentDailyOrderRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentDailyOrderCount()),(10*sortNo++),true);

            String studentDailyOrderRate = calculateRate(ungroupedStats.getStudentDailyOrderCount(), ungroupedStats.getStudentDailyCount());
            setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率（当日）", UNGROUPED_NAME, studentDailyOrderRate,(10*sortNo++));
            setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量（当日）", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentDailyOrderCount()),(10*sortNo++),true);
        }

        // 将 Map 转换为 List 返回
        return new ArrayList<>(indicatorMap.values());
    }

    /**
     * 设置指标值到对应的 CustomerStatisticsData 对象
     * @param indicatorMap 指标映射表
     * @param indicatorName 指标名称（不带组名前缀）
     * @param groupName 组名
     * @param value 指标值
     */
    private void setIndicatorValue(String corpId,Map<String, CustomerStatisticsData> indicatorMap,Date curDate,
                                   String indicatorName, String groupName, String value,int sortNo) {
        // 获取或创建该指标对应的 CustomerStatisticsData 对象
        CustomerStatisticsData vo = indicatorMap.computeIfAbsent(indicatorName, k -> {
            CustomerStatisticsData newVo = new CustomerStatisticsData();
            newVo.setIndicatorName(indicatorName);
            newVo.setCurDate(curDate);
            newVo.setSortNo(sortNo);
            newVo.setCorpId(corpId);
            return newVo;
        });

        // 根据组名设置对应的字段值
        setGroupValue(vo, groupName, value);
    }

    /**
     * 设置指标值到对应的 CustomerStatisticsData 对象
     * @param indicatorMap 指标映射表
     * @param indicatorName 指标名称（不带组名前缀）
     * @param groupName 组名
     * @param value 指标值
     */
    private void setIndicatorValue(String corpId, Map<String, CustomerStatisticsData> indicatorMap, Date curDate,
                                   String indicatorName, String groupName, String value, int sortNo, Boolean hiddenFlag) {
        // 获取或创建该指标对应的 CustomerStatisticsData 对象
        CustomerStatisticsData vo = indicatorMap.computeIfAbsent(indicatorName, k -> {
            CustomerStatisticsData newVo = new CustomerStatisticsData();
            newVo.setIndicatorName(indicatorName);
            newVo.setCurDate(curDate);
            newVo.setSortNo(sortNo);
            newVo.setCorpId(corpId);
            newVo.setHiddenFlag(hiddenFlag);
            return newVo;
        });

        // 根据组名设置对应的字段值
        setGroupValue(vo, groupName, value);
    }

    /**
     * 根据组名设置对应字段的值
     * @param vo CustomerStatisticsData 对象
     * @param groupName 组名
     * @param value 要设置的值
     */
    private void setGroupValue(CustomerStatisticsData vo, String groupName, String value) {
        switch (groupName) {
            case "N组":
                vo.setNtfGroup(value);
                break;
            case "O组":
                vo.setOfhGroup(value);
                break;
            case "P组":
                vo.setPswGroup(value);
                break;
            case "W组":
                vo.setWa1Group(value);
                break;
            case "X组":
                vo.setXb1Group(value);
                break;
            case "Y组":
                vo.setYc1Group(value);
                break;
            case "Z组":
                vo.setZd1Group(value);
                break;
            case "AA组":
                vo.setAaGroup(value);
                break;
            case "AC组":
                vo.setAcGroup(value);
                break;
            case "AD组":
                vo.setAdGroup(value);
                break;
            case "AE组":
                vo.setAeGroup(value);
                break;
        }
    }

    /**
     * 计算百分比
     */
    private String calculateRate(int count, int total) {
        if (total == 0) {
            return "0%";
        }
        BigDecimal rate = new BigDecimal(count)
                .multiply(new BigDecimal(100))
                .divide(new BigDecimal(total), 2, RoundingMode.HALF_UP);
        return rate.toString() + "%";
    }


    /**
     * 处理单条数据记录，累加到部门统计中
     * 修复：添加对tag_group7成单状态的验证
     */
    private void processDepartmentRecord(CustomerExportData data, Date targetDate,
                                        DepartmentStatisticsAccumulator.DepartmentStats stats) {
        // 成单统计：需要同时满足成交日期匹配 AND 成单状态匹配
        if(matchesQValue(data,targetDate) && isOrderCompleted(data)) {
            stats.setTotalOrderCount(stats.getTotalOrderCount() + 1);

            // 及时单和非及时单统计
            String orderStatus = data.getTagGroup7();
            if (orderStatus != null) {
                String[] split = orderStatus.split(",");
                if (split[split.length-1].contains("已成交及时单9元+")) {
                    stats.setTimelyOrderCount(stats.getTimelyOrderCount() + 1);
                } else if (split[split.length-1].contains("已成交非及时单9元+")) {
                    stats.setNonTimelyOrderCount(stats.getNonTimelyOrderCount() + 1);
                }
            }
        }

        if (matchesDate(data,targetDate)) {
            if(matchesSource(data)) {
                // 2. 总承接数（当日）- 排除"由管理员XXX分配"
                stats.setTotalAcceptCount(stats.getTotalAcceptCount() + 1);

                // 新增：家长/学生出单率统计
                String customerAttr = data.getTagGroup6();
                if (customerAttr != null && !customerAttr.trim().isEmpty()) {
                    if (customerAttr.contains("家长")) {
                        stats.setParentDailyCount(stats.getParentDailyCount() + 1);
                        if (matchesQValue(data, targetDate) && isTimelyOrder(data)) {
                            stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
                        }
                    } else if (customerAttr.contains("学生")) {
                        stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
                        if (matchesQValue(data, targetDate) && isTimelyOrder(data)) {
                            stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
                        }
                    }
                }
            } else {
                // 由管理员XXX分配"
                stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
            }
        }
    }

    /**
     * 从累加器生成最终部门统计结果
     * 每一行数据代表一个部门或员工，包含所有指标维度
     */
    private List<DepartmentStatisticsData> generateDepartmentStatisticsResults(String corpId,
            DepartmentStatisticsAccumulator accumulator, Date statDate) {
        List<DepartmentStatisticsData> results = new ArrayList<>();

        int sortNo = 0;
        // 为每个部门生成一条记录，包含所有指标
        for (Map.Entry<String, DepartmentStatisticsAccumulator.DepartmentStats> entry :
                accumulator.getDepartmentStatsMap().entrySet()) {
            String departmentPath = entry.getKey();
            DepartmentStatisticsAccumulator.DepartmentStats stats = entry.getValue();

            // 创建一个DepartmentStatisticsData对象，包含所有指标
            DepartmentStatisticsData vo = new DepartmentStatisticsData();
            vo.setStatDate(statDate);
            vo.setDepartmentPath(departmentPath);
            vo.setCorpId(corpId);

            // 解析路径，设置各级名称
            // 路径格式：苏州曼普/销售部/二组/盛宇婷
            String[] pathParts = departmentPath.split("/");
            if (pathParts.length >= 1) {
                vo.setCorpName(pathParts[0]);
            }
            if (pathParts.length >= 2) {
                vo.setDepartmentName(pathParts[1]);
            }
            if (pathParts.length >= 3) {
                vo.setGroupName(pathParts[2]);
            }
            if (pathParts.length >= 4) {
                vo.setPersonName(pathParts[3]);
                vo.setPersonFlag(true);
            } else {
                vo.setPersonFlag(false);
            }

            // 设置各项指标
            // 1. 总承接数（当日）
            vo.setDailyTotalAccepted(stats.getTotalAcceptCount());
            //设置管理员分配人数
            vo.setManagerAccepted(stats.getManagerAcceptCount());

            // 2. 总成单数（当日）
            vo.setDailyTotalOrders(stats.getTotalOrderCount());

            // 3. 转化率（当日）
            BigDecimal conversionRate = calculateRateBigDecimal(stats.getTotalOrderCount(), stats.getTotalAcceptCount());
            vo.setDailyConversionRate(conversionRate);

            // 4. 及时单占比（当日）
            BigDecimal timelyRate = calculateRateBigDecimal(stats.getTimelyOrderCount(), stats.getTotalOrderCount());
            vo.setDailyTimelyCount(stats.getTimelyOrderCount());
            vo.setDailyTimelyOrderRatio(timelyRate);

            // 5. 非及时单占比（当日）
            BigDecimal nonTimelyRate = calculateRateBigDecimal(stats.getNonTimelyOrderCount(), stats.getTotalOrderCount());
            vo.setDailyNonTimelyCount(stats.getNonTimelyOrderCount());
            vo.setDailyNonTimelyOrderRatio(nonTimelyRate);

            // 6. 家长出单率（当日）
            BigDecimal parentOrderRate = calculateRateBigDecimal(stats.getParentDailyOrderCount(), stats.getParentDailyCount());
            vo.setParentDailyOrderCount(stats.getParentDailyOrderCount());
            vo.setParentDailyCount(stats.getParentDailyCount());
            vo.setDailyParentOrderRate(parentOrderRate);

            // 7. 学生出单率（当日）
            BigDecimal studentOrderRate = calculateRateBigDecimal(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount());
            vo.setStudentDailyOrderCount(stats.getStudentDailyOrderCount());
            vo.setStudentDailyCount(stats.getStudentDailyCount());
            vo.setDailyStudentOrderRate(studentOrderRate);

            results.add(vo);
        }

        return results;
    }

    /**
     * 计算百分比（返回BigDecimal类型）
     */
    private BigDecimal calculateRateBigDecimal(int count, int total) {
        if (total == 0) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(count)
                .multiply(new BigDecimal(100))
                .divide(new BigDecimal(total), 2, RoundingMode.HALF_UP);
    }

}
