package com.awspaas.user.apps.bnbm.datalinkup.service.impl;

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.commons.database.DBUtils;
import com.actionsoft.bpms.commons.database.RowMap;
import com.actionsoft.bpms.commons.pagination.SQLPagination;
import com.actionsoft.bpms.server.UserContext;
import com.actionsoft.bpms.util.DBSql;
import com.actionsoft.bpms.util.UtilDate;
import com.actionsoft.sdk.local.SDK;
import com.actionsoft.sdk.local.api.cc.RDSAPI;
import com.awspaas.user.apps.bnbm.datalinkup.entity.DateRange;
import com.awspaas.user.apps.bnbm.datalinkup.service.DataSyncService;
import com.awspaas.user.apps.bnbm.datalinkup.util.PurchaseUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.awspaas.user.apps.bnbm.datalinkup.util.PurchaseUtil.isEqual;

/**
 * @ClassName: ProductionDataSyncServiceImpl
 * @Description: 生产实现类
 * @date: 2025/8/25 13:41
 * @Blog: https://
 */
public class ProductionDataSyncServiceImpl implements DataSyncService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ProductionDataSyncServiceImpl.class);
    /**
     * 时间范围常量：同步最近60天数据（不包括当天）
     */
    private static final int DAYS_BACK = Integer.parseInt(SDK.getAppAPI().getProperty("com.awspaas.user.apps.bnbm.datalinkup", "days_back"));

    /**
     * 增加分页大小常量
     */
    private static final int PAGE_SIZE = 10000; // 每页查询1000条记录

    private static final String ORACLE_DATE_FORMAT = "YYYY-MM-DD HH24:MI:SS";
    private static final String SEND_EMAIL_ACCOUNT_NUMBER = SDK.getAppAPI().getProperty("com.awspaas.user.apps.bnbm.datalinkup","sendEmailAccountNumber");
    private static final String RECEIVE_EMAIL_ACCOUNT = SDK.getAppAPI().getProperty("com.awspaas.user.apps.bnbm.datalinkup","RECEIVE_EMAIL_ACCOUNT");

    @Override
    public ArrayList<DateRange> syncDataByConfigs(List<BO> configs) {
        ArrayList<DateRange> list = new ArrayList<>();
        if (configs.isEmpty()) {
            LOGGER.info("未找到有效的同步配置");
            return list;
        }

        // 按所属板块(SSBK)分组配置
        Map<String, List<BO>> configsByPlate = configs.stream()
                .collect(Collectors.groupingBy(bo -> bo.getString("SSBK")));
        // 遍历处理每个板块的配置
        for (Map.Entry<String, List<BO>> entry : configsByPlate.entrySet()) {
            String plate = entry.getKey();
            List<BO> plateConfigs = entry.getValue();
            LOGGER.info("处理板块【{}】的{}条配置", plate, plateConfigs.size());

            // 处理当前板块的每条配置
            boolean connectionFailed = false;
            String errorMsg = "";
            for (BO mainConfig : plateConfigs) {
                try {
                    DateRange dateRange = processMainConfig(mainConfig);
                    list.add(dateRange);
                } catch (Exception e) {
                    LOGGER.error("处理配置失败 [板块={}, BindID={}]: {}",
                            plate, mainConfig.getString("BINDID"), e.getMessage(), e);
                }
            }
        }
        return list;
    }

    @Override
    public DateRange processMainConfig(BO mainConfig) {
        String bindId = mainConfig.getString("BINDID");
        String tableName = mainConfig.getString("TBB");
        String timeField = mainConfig.getString("SJZD");
        String targetTable = mainConfig.getString("LDB");
        String ccId = mainConfig.getString("CC_ID");
        String partitionField = mainConfig.getString("FQBZD");
        String bkgs = mainConfig.getString("BKGS");
        String jezd = mainConfig.getString("JEZD");
        DateRange dateRange = new DateRange();

        LOGGER.info("处理配置：BindID={}, 源表={}, 目标表={}, CC_ID={}, 时间字段={}, 分区字段配置={}",
                bindId, tableName, targetTable, ccId,timeField,partitionField);

        // 查询子表字段映射配置
        List<BO> fieldMappings = SDK.getBOAPI()
                .query("BO_EU_BNBM_DATALINKUP_SJGTPZ_SUB")
                .addQuery("BINDID =", bindId)
                .list();

        if (fieldMappings.isEmpty()) {
            LOGGER.warn("未找到BindID={}的字段映射配置", bindId);
            return dateRange;
        }

        // 根据时间字段是否为空设置日期范围
        Date startDate = null;
        Date endDate = null;

        // 删除目标表数据（根据时间字段是否为空决定删除范围）
        if (timeField == null || timeField.isEmpty()) {
            // 全量删除
            deleteAllTargetData(targetTable);
        } else {
            // 计算时间范围（当前日期-30天 ~ 昨天）
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.DATE, -1); // 昨天
            endDate = cal.getTime();
            cal.add(Calendar.DATE, -DAYS_BACK + 1); // 30天前（含）
            startDate = cal.getTime();

            // 获取目标表时间字段名
            String targetTimeField = getTargetTimeField(fieldMappings, timeField);
            if (targetTimeField == null) {
                LOGGER.error("无法找到源时间字段[{}]对应的目标表字段，跳过同步", timeField);
                return dateRange;
            }
            // 按时间范围删除
            deleteTargetData(targetTable, targetTimeField, startDate, endDate);
        }
        querySourceData(ccId, tableName, timeField, startDate, endDate, partitionField,
                fieldMappings, targetTable,jezd);
        dateRange.setStartDate(startDate);
        dateRange.setEndDate(endDate);
        return dateRange;

    }

    /**
     * 获取目标表时间字段名
     * @param mappings 字段映射配置列表
     * @param sourceTimeField 源表时间字段名
     * @return 目标表时间字段名，未找到返回null
     */
    @Override
    public String getTargetTimeField(List<BO> mappings, String sourceTimeField) {
        for (BO mapping : mappings) {
            if (sourceTimeField.equals(mapping.getString("TBBZD"))) {
                return mapping.getString("LDBZD");
            }
        }
        return null;
    }

    /**
     * 删除目标表中指定时间范围的数据
     * @param targetTable 目标表名
     * @param targetTimeField 目标表时间字段名
     * @param startDate 开始时间
     * @param endDate 结束时间
     * @throws RuntimeException 删除失败时抛出
     */
    @Override
    public void deleteTargetData(String targetTable, String targetTimeField,
                                 Date startDate, Date endDate) {
        try {
            String deleteSql = "DELETE FROM " + targetTable +
                    " WHERE " + targetTimeField + " >= ? ";
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String startDateStr = simpleDateFormat.format(startDate)+" 00:00:00";
            String endDateStr = simpleDateFormat.format(endDate)+" 23:59:59";
            int deletedCount = DBSql.update(deleteSql, new Object[]{startDateStr});
            LOGGER.info("已删除目标表[{}]中{}条数据（时间范围: {} ）",
                    targetTable, deletedCount, startDateStr);
        } catch (Exception e) {
            throw new RuntimeException("删除目标表数据失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void deleteAllTargetData(String targetTable) {
        try {
            String deleteSql = "DELETE FROM " + targetTable ;
            int deletedCount = DBSql.update(deleteSql);
            LOGGER.info("已全量删除目标表[{}]中{}条数据", targetTable, deletedCount);
        } catch (Exception e) {
            throw new RuntimeException("全量删除目标表数据失败: " + e.getMessage(), e);
        }
    }

    /**
     * 跨库查询源表数据
     * @param ccId 跨库连接ID
     * @param tableName 源表名
     * @param timeField 源表时间字段名
     * @param startDated 开始时间
     * @param endDated 结束时间
     * @return 查询结果数据集
     * @throws RuntimeException 查询失败或参数无效时抛出
     */
    @Override
    public void querySourceData(String ccId, String tableName,
                                String timeField, Date startDated, Date endDated,String partitionField,
                                List<BO> fieldMappings, String targetTable,String jezd) {
//        LOGGER.info("ccId:{},tableName:{},timeField:{},startDated:{},endDated:{},partitionField:{},fieldMappings:{},targetTable:{},jezd:{}",ccId,tableName,timeField,startDated,endDated,partitionField,Arrays.asList(fieldMappings.toArray()),targetTable,jezd);
        int totalRows = 0;      // 总查询行数
        int totalSuccess = 0;   // 总成功插入行数
        int pageNo = 1;
        boolean hasMore;
        RDSAPI rdsapi = null;
        DBUtils.SUPPLY supply = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd");
        // 重试配置
        int maxRetries = 3;
        int retryDelayMs = 2000; // 重试延迟2秒
        try {
            // 带重试机制的连接获取
            for (int retry = 0; retry < maxRetries; retry++) {
                try {
                    rdsapi = SDK.getCCAPI().getRDSAPI(ccId);
                    supply = rdsapi.getSupply();
                    if (rdsapi != null && supply!=null) {
                        break; // 连接成功，跳出重试循环
                    }
                } catch (Exception e) {
                    if (retry == maxRetries - 1) {
                        String result = fieldMappings.stream()
                                .filter(bo -> "BKGS".equals(bo.getString("LDBZD")))   // 条件1: LDBZD 为 "BKGS"
                                .filter(bo -> bo.getString("LDZDMRZ") != null)        // 条件2: LDZDMRZ 不为空
                                .map(bo -> bo.getString("LDZDMRZ"))                          // 提取 LDZDMRZ 的值
                                .collect(Collectors.joining());                // 收集到 List
                        // 最后一次重试仍然失败
                        String errorMsg = String.format("获取数据库连接失败(CC_ID: %s)，板块为：%s，已重试%d次，同步时间为：%s\n错误信息为：%s",
                                ccId, result, maxRetries, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), e.getMessage());
                        LOGGER.error(errorMsg, e);
                        // 发送邮件通知
//                        boolean eMailSync = SDK.getNotificationAPI().sendEMailSync(SEND_EMAIL_ACCOUNT_NUMBER, RECEIVE_EMAIL_ACCOUNT, null, "数据贯通数据库连接通知", errorMsg);
//                        if (eMailSync){
//                            LOGGER.info("短信发送成功");
//                        }else {
//                            LOGGER.info("短信发送失败");
//                        }
                        throw new RuntimeException(errorMsg, e);
                    }
                    LOGGER.warn("获取数据库连接失败(CC_ID: {})，第{}次重试...", ccId, retry + 1);
                    Thread.sleep(retryDelayMs);
                }
            }
            String DBname = supply.getName();
            LOGGER.info("数据库为：{}",DBname);

            // 计算时间范围并拆分为30天一组
            List<Date[]> timeRanges = splitTimeRange(startDated, endDated, 30);
            LOGGER.info("时间范围拆分为 {} 个查询区间", timeRanges.size());

            String maxPartition = "";
            if (partitionField != null && !partitionField.isEmpty()) {
                // 1. 查询最大分区值
                String maxPartitionSql = "SELECT MAX(" + partitionField + ") AS max_partition FROM " + tableName;
                List<RowMap> maxPartitionResult = rdsapi.getMaps(maxPartitionSql);

                if (maxPartitionResult.isEmpty() || maxPartitionResult.get(0).get("max_partition") == null) {
                    LOGGER.warn("表[{}]没有找到分区字段[{}]的数据", tableName, partitionField);
                    return;
                }

                maxPartition = maxPartitionResult.get(0).getString("max_partition");
                LOGGER.info("表[{}]的最大分区为: {}", tableName, maxPartition);
            }


            for (int i = 0; i < timeRanges.size(); i++) {
                Date[] range = timeRanges.get(i);
                String startDate = simpleDateFormat2.format(range[0])+" 00:00:00";
                String endDate = simpleDateFormat2.format(range[1])+" 23:59:59";

                LOGGER.info("正在处理第 {} 个时间区间: {} 至 {}", i + 1, startDate, endDate);
                if ("ORACLE".equalsIgnoreCase(DBname)) {
                    // 构建查询条件
                    StringBuilder conditionBuilder = new StringBuilder();
                    StringBuilder orderByBuilder = new StringBuilder(); // 用于构建排序子句
                    List<Object> params = new ArrayList<>(); // 存储查询参数

                    // 分区字段和时间字段组合查询条件
                    if (partitionField != null && !partitionField.isEmpty()) {

                        // 添加分区条件
                        conditionBuilder.append(partitionField)
                                .append(" = '")
                                .append(maxPartition)
                                .append("'");

                        // 如果时间字段存在，添加时间范围条件
                        if (timeField != null && !timeField.isEmpty()) {
                            conditionBuilder.append("TO_DATE(")
                                    .append(timeField)
                                    .append(", '")
                                    .append(ORACLE_DATE_FORMAT)
                                    .append("') >= TO_DATE(?, '")
                                    .append(ORACLE_DATE_FORMAT)
                                    .append("') AND TO_DATE(")
                                    .append(timeField)
                                    .append(", '")
                                    .append(ORACLE_DATE_FORMAT)
                                    .append("') < TO_DATE(?, '")
                                    .append(ORACLE_DATE_FORMAT)
                                    .append("')");

                            // 构建排序子句
                            orderByBuilder.append(" ORDER BY ").append(timeField);
                            if (jezd != null && !jezd.isEmpty()) {
                                orderByBuilder.append(", ").append(jezd);
                            }
                            orderByBuilder.append(" DESC");
                            params.add(startDate);
                            params.add(endDate);
                        }
                    } else if (timeField != null && !timeField.isEmpty()) {
                        // 没有分区字段，但时间字段存在，使用时间范围条件
                        // 仅时间范围条件（使用占位符）
                        conditionBuilder.append("TO_DATE(")
                                .append(timeField)
                                .append(", '")
                                .append(ORACLE_DATE_FORMAT)
                                .append("') >= TO_DATE(?, '")
                                .append(ORACLE_DATE_FORMAT)
                                .append("') AND TO_DATE(")
                                .append(timeField)
                                .append(", '")
                                .append(ORACLE_DATE_FORMAT)
                                .append("') < TO_DATE(?, '")
                                .append(ORACLE_DATE_FORMAT)
                                .append("')");
                        // 构建排序子句
                        orderByBuilder.append(" ORDER BY ").append(timeField);
                        if (jezd != null && !jezd.isEmpty()) {
                            orderByBuilder.append(", ").append(jezd);
                        }
                        orderByBuilder.append(" DESC");
                        params.add(startDate);
                        params.add(endDate);
                    } else {
                        // 既没有分区字段也没有时间字段，查询全表
                        LOGGER.warn("警告：未配置分区字段和时间字段，将查询全表数据！");
                        conditionBuilder.append("1=1");
                    }

                    // 分页查询数据
                    do {
                        // 使用Oracle分页语法 (12c+)
                        String querySql = "SELECT * FROM " + tableName +
                                " WHERE " + conditionBuilder.toString() +
                                orderByBuilder.toString(); // 添加排序子句

                        LOGGER.debug("执行Oracle查询: {}", querySql);

                        List<RowMap> pageData;
                        // 根据条件类型执行查询
                        if (partitionField != null && !partitionField.isEmpty() &&
                                timeField != null && !timeField.isEmpty()) {
                            // 分区+时间范围查询
                            pageData = rdsapi.getMaps(querySql, startDate, endDate);
                        } else if (timeField != null && !timeField.isEmpty()) {
                            // 仅时间范围查询
                            pageData = rdsapi.getMaps(querySql, startDate, endDate);
                        } else {
                            // 无时间范围查询（仅分区或全表）
                            pageData = rdsapi.getMaps(querySql);
                        }

                        if (pageData != null && !pageData.isEmpty()) {
                            // 直接处理当前页数据
                            int successCount = this.processAndInsertData(pageData, fieldMappings, targetTable);
                            totalRows += pageData.size();
                            totalSuccess += successCount;
                            hasMore = pageData.size() == PAGE_SIZE;
                            pageNo++;
                        } else {
                            hasMore = false;
                        }
                    } while (hasMore);
                } else {
                    // 构建查询条件
                    StringBuilder conditionBuilder = new StringBuilder();
                    // 修改点：分区字段和时间字段组合查询条件
                    if (partitionField != null && !partitionField.isEmpty()) {

                        // 添加分区条件
                        conditionBuilder.append(partitionField)
                                .append(" = '")
                                .append(maxPartition)
                                .append("'");

                        // 如果时间字段存在，添加时间范围条件
                        if (timeField != null && !timeField.isEmpty()) {
                            conditionBuilder.append(" AND ")
                                    .append(timeField).append(" >= ?")
                                    .append(" AND ")
                                    .append(timeField).append(" < ?")
                                    .append(" ORDER BY ").append(timeField);
                            //.append(" BETWEEN ? AND ? ORDER BY " + timeField + "");
                            if (jezd != null && !jezd.isEmpty()) {
                                conditionBuilder.append(", " + jezd + " ");
                            }
                            conditionBuilder.append(" DESC");
                        }
                    } else if (timeField != null && !timeField.isEmpty()) {
                        // 没有分区字段，但时间字段存在，使用时间范围条件
                        /*conditionBuilder.append(timeField)
                                .append(" BETWEEN ? AND ? ORDER BY " + timeField + "");*/
                        conditionBuilder.append(timeField).append(" >= ?")
                                .append(" AND ")
                                .append(timeField).append(" < ?")
                                .append(" ORDER BY ").append(timeField);
                        if (jezd != null && !jezd.isEmpty()) {
                            conditionBuilder.append(", " + jezd + " ");
                        }
                        conditionBuilder.append(" DESC");
                    } else {
                        // 既没有分区字段也没有时间字段，查询全表（实际应避免这种情况）
                        LOGGER.warn("警告：未配置分区字段和时间字段，将查询全表数据！");
                        conditionBuilder.append("1=1");
                    }
                    // 分页查询数据
                    do {
                        String querySql = "SELECT * FROM " + tableName +
                                " WHERE " + conditionBuilder.toString();

                        LOGGER.debug("执行查询querySql: {}", querySql);

                        List<RowMap> pageData;
                        // 根据条件类型执行查询
                        if (partitionField != null && !partitionField.isEmpty() &&
                                timeField != null && !timeField.isEmpty()) {
                            // 分区+时间范围查询
                            pageData = rdsapi.getMaps(querySql, startDate, endDate);
                        } else if (timeField != null && !timeField.isEmpty()) {
                            // 仅时间范围查询
                            pageData = rdsapi.getMaps(querySql, startDate, endDate);
                        } else {
                            // 无时间范围查询（仅分区或全表）
                            pageData = rdsapi.getMaps(querySql);
                        }

                        if (pageData != null && !pageData.isEmpty()) {
                            // 直接处理当前页数据
                            int successCount = this.processAndInsertData(pageData, fieldMappings, targetTable);
                            totalRows += pageData.size();
                            totalSuccess += successCount;
                            hasMore = pageData.size() == PAGE_SIZE;
                            pageNo++;
                        } else {
                            hasMore = false;
                        }
                    } while (hasMore);
                }
            }
            LOGGER.info("从表[{}]共查询到{}条数据，成功同步{}条数据",
                    tableName, totalRows, totalSuccess);
        } catch (Exception e) {
            throw new RuntimeException("查询源表[" + tableName + "]数据失败: " + e.getMessage(), e);
        }
    }

    /**
     * 处理并插入数据到目标表
     * @param sourceData 源数据列表
     * @param mappings 字段映射配置
     * @param targetTable 目标表名
     */
    public int processAndInsertData(List<RowMap> sourceData,
                                    List<BO> mappings, String targetTable) {
        String bkgs = "";
        Set<String> bkgsSet = null;
        LOGGER.info("当前查询到的数据中的板块：{}",bkgs);
        if (sourceData.isEmpty()) {
            LOGGER.info("没有需要同步的数据");
            return 0;
        }

        List<BO> batchList = new ArrayList<>();
        int successCount = 0;
        int totalCount = sourceData.size();
        int processedCount = 0; // 已处理记录数

        for (int i = 0; i < totalCount; i++) {
            RowMap record = sourceData.get(i);
            processedCount++; // 增加已处理计数
            try {
                // 字段映射转换
                BO targetData = convertFields(record, mappings);
                batchList.add(targetData);

                // 批量插入条件：达到批处理大小或最后一条
                if (batchList.size() >= PAGE_SIZE || i == totalCount - 1) {
                    // 使用管理员权限批量插入
                    SDK.getBOAPI().createDataBO(targetTable, batchList, UserContext.fromUID("admin"));
                    successCount += batchList.size();
                    bkgsSet = sourceData.stream().map(o->o.getString("BKGS")).distinct().collect(Collectors.toSet());
                    batchList.clear(); // 清空批次
                }
            } catch (Exception e) {
                LOGGER.error("数据处理失败: {}", e.getMessage(), e);
            }
        }
        // 增加详细日志输出：共处理多少条，成功同步多少条
        bkgs = bkgsSet.toArray().toString();
        LOGGER.info("同步板块为：{}；落地表为：{}，本次处理{}条数据，成功同步{}条数据到表[{}]",
                bkgs,targetTable,processedCount, successCount, targetTable);
        return successCount;
    }

    /**
     * 将时间范围拆分为多个区间，确保区间连续（下一个区间的开始时间 = 上一个区间的结束时间）且无重叠
     * 所有日期均强制转换为 yyyy-MM-dd 格式（时间部分固定为 00:00:00）
     * @param startDate 开始时间（建议传入 yyyy-MM-dd 格式，若含时间部分会自动截断为 00:00:00）
     * @param endDate 结束时间（建议传入 yyyy-MM-dd 格式，若含时间部分会自动截断为 00:00:00）
     * @param daysInterval 每个区间的间隔天数（例如：传入 7 表示每个区间覆盖 7 天，如 2024-01-01~2024-01-08）
     * @return 时间区间列表，每个元素为 [开始时间, 结束时间]，均为 yyyy-MM-dd 00:00:00 格式
     */
    public static List<Date[]> splitTimeRange(Date startDate, Date endDate, int daysInterval) {
        // 1. 入参合法性校验：避免无效区间或负间隔
        if (startDate == null || endDate == null) {
            throw new IllegalArgumentException("开始时间和结束时间不可为 null");
        }
        if (daysInterval < 1) {
            throw new IllegalArgumentException("间隔天数必须大于等于 1");
        }
        // 2. 初始化日历并强制截断时间部分（确保所有日期都是 yyyy-MM-dd 00:00:00）
        Calendar calendar = Calendar.getInstance();
        setTimeToStartOfDay(calendar); // 先重置时间，再设日期（避免原日期含时间的影响）
        calendar.setTime(startDate);
        Date currentStart = calendar.getTime();

        Calendar endCal = Calendar.getInstance();
        setTimeToStartOfDay(endCal);
        endCal.setTime(endDate);
        Date finalEnd = endCal.getTime();
        // 额外校验：开始时间不能晚于结束时间
        if (currentStart.after(finalEnd)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        List<Date[]> ranges = new ArrayList<>();
        // 3. 循环拆分区间：核心逻辑确保“下一个开始 = 上一个结束”
        while (true) {
            // 计算当前区间的结束时间：开始时间 + 间隔天数（如 2024-01-01 + 7天 = 2024-01-08）
            calendar.add(Calendar.DAY_OF_MONTH, daysInterval);
            setTimeToStartOfDay(calendar); // 再次确保时间部分为 00:00:00
            Date currentEnd = calendar.getTime();
            // 处理最后一个区间：若计算的结束时间超过最终结束时间，强制对齐到 finalEnd
            if (currentEnd.after(finalEnd)) {
                currentEnd = finalEnd;
            }
            // 添加当前区间 [currentStart, currentEnd]
            ranges.add(new Date[]{currentStart, currentEnd});
            // 终止条件：当前区间的结束时间已等于最终结束时间，无需继续拆分
            if (currentEnd.equals(finalEnd)) {
                break;
            }
            // 准备下一个区间的开始时间：当前结束时间（满足“连续”要求）
            currentStart = currentEnd;
        }

        return ranges;
    }

    /**
     * 工具方法：将 Calendar 的时间部分强制设置为当天 00:00:00（截断时分秒毫秒）
     * @param calendar 待处理的 Calendar 实例（非 null）
     */
    private static void setTimeToStartOfDay(Calendar calendar) {
        if (calendar == null) {
            throw new IllegalArgumentException("Calendar 实例不可为 null");
        }
        calendar.set(Calendar.HOUR_OF_DAY, 0);  // 24小时制，0 表示凌晨 0 点
        calendar.set(Calendar.MINUTE, 0);       // 分钟设为 0
        calendar.set(Calendar.SECOND, 0);       // 秒设为 0
        calendar.set(Calendar.MILLISECOND, 0);  // 毫秒设为 0
    }

    /**
     * 字段映射转换
     * @param source 源数据记录
     * @param mappings 字段映射配置
     * @return 转换后的BO对象
     */
    public BO convertFields(RowMap source, List<BO> mappings) {
        BO target = new BO();

        for (BO mapping : mappings) {
            String sourceField = mapping.getString("TBBZD");
            String targetField = mapping.getString("LDBZD");

            String operationExpr = mapping.getString("TBBZDJSLJ");
            if (StringUtils.isNotBlank(operationExpr)) {
                // 解析运算表达式 (格式: [运算符][数字])
                char operator = operationExpr.charAt(0);
                String numberPart = operationExpr.substring(1);

                try {
                    // 获取源值并转换为BigDecimal
                    String sourceValue = source.getString(sourceField);
                    if (StringUtils.isBlank(sourceValue)) {
                        target.set(targetField, null);
                        continue;
                    }

                    if ("GG".equals(sourceField)){
                        String string = source.getString(sourceField);
                        if (StringUtils.isNotBlank(string) && string.contains("×")){
                            String[] split = string.split("×");
                            String s = split[split.length - 1];
                            target.set(targetField, s);
                            continue;
                        }
                    }

                    BigDecimal sourceNum = new BigDecimal(sourceValue);
                    BigDecimal operand = new BigDecimal(numberPart);
                    BigDecimal result;

                    // 执行相应运算
                    switch (operator) {
                        case '*':
                            result = sourceNum.multiply(operand);
                            break;
                        case '/':
                            if (BigDecimal.ZERO.compareTo(operand) == 0) {
                                LOGGER.error("除零错误: 源字段[{}] 除数为0", sourceField);
                                result = sourceNum; // 避免除零异常
                            } else {
                                // 除法保留10位小数并四舍五入
                                result = sourceNum.divide(operand, 10, RoundingMode.HALF_UP);
                            }
                            break;
                        case '+':
                            result = sourceNum.add(operand);
                            break;
                        case '-':
                            result = sourceNum.subtract(operand);
                            break;
                        default:
                            LOGGER.error("未知运算符: {} 字段[{}]", operator, sourceField);
                            result = sourceNum;
                    }
                    target.set(targetField, result);
                } catch (NumberFormatException e) {
                    LOGGER.error("数值转换失败: 源字段[{}]={}, 操作数={}",
                            sourceField, source.getString(sourceField), numberPart, e);
                    target.set(targetField, source.getString(sourceField));
                }
            } else {
                if ("GG".equals(sourceField)){
                    String string = source.getString(sourceField);
                    if (StringUtils.isNotBlank(string) && string.contains("×")){
                        String[] split = string.split("×");
                        String s = split[split.length - 1];
                        target.set(targetField, s);
                    }else {
                        // 无运算表达式时直接复制原始值
                        target.set(targetField, StringUtils.isNotBlank(string)?string:"");
                    }
                }else {
                    // 无运算表达式时直接复制原始值
                    target.set(targetField, source.getString(sourceField));
                }
            }
            String ldzdmrz = mapping.getString("LDZDMRZ");
            if (StringUtils.isNotBlank(ldzdmrz)){
                target.set(mapping.getString("LDBZD"),ldzdmrz);
            }
        }
        return target;
    }

    /**
     * 销售各板块数据汇总表
     * @param configs
     */
    @Override
    public void sumBkTable(List<BO> configs) {
        Map<String, List<BO>> configsByPlate = configs.stream()
                .collect(Collectors.groupingBy(bo -> bo.getString("SSBK")));

        // 遍历处理每个板块的配置
        for (Map.Entry<String, List<BO>> entry : configsByPlate.entrySet()) {
            String plate = entry.getKey();
            List<BO> plateConfigs = entry.getValue();
            LOGGER.info("处理板块【{}】的{}条配置", plate, plateConfigs.size());

            // 处理当前板块的每条配置
            for (BO mainConfig : plateConfigs) {
                String targetTable = mainConfig.getString("LDB");//落地表
                String timeField = mainConfig.getString("SJZD");//时间字段
                String bindId = mainConfig.getString("BINDID");//bindid
                String tablename = mainConfig.getString("TABLENAME");//同步表名
                String hzb = "";
                try {
                    if ("生产入库".equals(tablename)) {
                        hzb = "BO_EU_BNBM_SCRK_HZ";
                    } else if ("生产出库".equals(tablename)) {
                        hzb = "BO_EU_BNBM_SCCK_HZ";
                    }else {
                        continue;
                    }
                    // 查询子表字段映射配置
                    List<BO> fieldMappings = SDK.getBOAPI()
                            .query("BO_EU_BNBM_DATALINKUP_SJGTPZ_SUB")
                            .addQuery("BINDID =", bindId)
                            .list();
                    //获取板块公司
                    String bkgs = DBSql.getString("SELECT BKGS FROM " + targetTable, "BKGS");

                    // 根据时间字段是否为空设置日期范围
                    Date startDate = null;
                    Date endDate = null;

                    // 删除目标表数据（根据时间字段是否为空决定删除范围）
                    if (timeField == null || timeField.isEmpty()) {
                        // 全量删除
                        String deleteSql = "DELETE FROM "+hzb+" WHERE BKGS = '"+bkgs+"'";
                        int deletedCount = DBSql.update(deleteSql);
                        LOGGER.info("已删除目标表[{}}]中{}条数据（时间范围: {} - {})",
                                hzb,deletedCount, startDate, endDate);

                        // 根据时间范围增加数据分页查询数据存储到BO_EU_BNBM_DATALINKUP_XS_XSL_HZ
                        // 全量分页迁移数据到汇总表
                        summarizeScopeData(targetTable, null, null, null, hzb);
                    } else {
                        // 计算时间范围（当前日期-30天 ~ 昨天）
                        Calendar cal = Calendar.getInstance();
                        cal.add(Calendar.DATE, -1); // 昨天
                        endDate = cal.getTime();
                        cal.add(Calendar.DATE, -DAYS_BACK + 1); // 30天前（含）
                        startDate = cal.getTime();

                        // 获取目标表时间字段名
                        String targetTimeField = getTargetTimeField(fieldMappings, timeField);
                        if (targetTimeField == null) {
                            LOGGER.error("无法找到源时间字段[{}]对应的目标表字段，跳过同步", timeField);
                        }
                        // 按时间范围删除
                        String deleteSql = "DELETE FROM " + hzb +
                                " WHERE BKGS = '"+bkgs+"' AND " + targetTimeField + " >= ? ";
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        String startDateStr = simpleDateFormat.format(startDate)+" 00:00:00";
                        int deletedCount = DBSql.update(deleteSql, new Object[]{startDate});
                        LOGGER.info("已删除目标表[{}]中{}条数据（时间范围: {} ）",
                                hzb,deletedCount, startDate);

                        // 根据时间范围增加数据分页查询数据存储到BO_EU_BNBM_DATALINKUP_XS_XSL_HZ
                        // 按时间范围分页迁移数据到汇总表
                        summarizeScopeData(targetTable, startDate, endDate, targetTimeField, hzb);
                    }

                } catch (Exception e) {
                    LOGGER.error("处理配置失败 [板块={}, BindID={}]: {}",
                            plate, mainConfig.getString("BINDID"), e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 汇总各板块销售数据汇总
     * @param targetTable
     * @param startDated
     * @param endDated
     * @param targetTimeField
     */
    @Override
    public void summarizeScopeData(String targetTable, Date startDated, Date endDated, String targetTimeField, String hzb) {
//        LOGGER.info("targetTable:{},startDated:{},endDated:{},targetTimeField:{},hzb:{}",targetTable,startDated,endDated,targetTimeField,hzb);
        int pageNo = 1;
        boolean hasMore;
        String pageSql = "";
        List<RowMap> pageData = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String startDate = "";
        String endDate = "";
        PurchaseUtil purchaseUtil = new PurchaseUtil();
        try {
            do {
                if (startDated == null || endDated == null) {
                    pageSql = "SELECT * FROM " + targetTable +
                            " ORDER BY ID LIMIT " + PAGE_SIZE + " OFFSET " + (pageNo - 1) * PAGE_SIZE;
                    pageData = DBSql.getMaps(pageSql);
                } else {
                    startDate = simpleDateFormat.format(startDated)+" 00:00:00";
                    endDate = simpleDateFormat.format(endDated)+" 23:59:59";
                    pageSql = "SELECT * FROM " + targetTable +
                            " WHERE " + targetTimeField + " >= '" + startDate + "' " +
                            " ORDER BY ID LIMIT " + PAGE_SIZE + " OFFSET " + (pageNo - 1) * PAGE_SIZE;
                    LOGGER.info("执行查询的sql：{}", pageSql);
                    pageData = DBSql.getMaps(pageSql);
                }

                if (pageData.isEmpty()) break;

                List<BO> bos = new ArrayList<>();
                for (RowMap map : pageData) {
                    BO bo = new BO();
                    // 复制所有字段（排除系统字段）
                    for (String key : map.keySet()) {
                        if (!key.equalsIgnoreCase("ID") &&
                                !key.equalsIgnoreCase("ORGID") &&
                                !key.equalsIgnoreCase("CREATEDATE") &&
                                !key.equalsIgnoreCase("CREATEUSER") &&
                                !key.equalsIgnoreCase("UPDATEDATE") &&
                                !key.equalsIgnoreCase("UPDATEUSER") &&
                                !key.equalsIgnoreCase("ISEND") &&
                                !key.equalsIgnoreCase("BINDID")) {
                            if (StringUtils.isNotBlank(targetTimeField)) {
                                String targetTimeField1 = map.getString(targetTimeField);
                                Date parse = UtilDate.parse(targetTimeField1);
                                int year = UtilDate.getYear(parse);
                                String monthFormat = UtilDate.monthFormat(parse);
                                int day = UtilDate.getDay(parse);
                                bo.set("YEARMONTH", year + monthFormat);
                                bo.set("YEAR", year);
                                bo.set("MONTH", monthFormat);
                                bo.set("DAY", day);
                            }
                            bo.set(key, map.get(key));
                        }
                    }
                    // 如果是采购_入库单汇总  刷新石膏板种类
                    String newSgbzl = "";
                    String newSgbhd = "";//石膏板厚度
                    if (hzb.equals("BO_EU_BNBM_SCRK_HZ")) {
                        String bkgs = StringUtils.trimToEmpty(bo.getString("BKGS"));
                        String wlmc = StringUtils.trimToEmpty(bo.getString("WLMC"));
                        String wlfl = StringUtils.trimToEmpty(bo.getString("WLFL"));
                        String xl = StringUtils.trimToEmpty(bo.getString("XL"));
                        String pp = StringUtils.trimToEmpty(bo.getString("PP"));
                        String zl = StringUtils.trimToEmpty(bo.getString("ZL"));
                        String gg = StringUtils.trimToEmpty(bo.getString("GG"));
                        String rksl = StringUtils.trimToEmpty(bo.getString("RKSL"));
                        if (bkgs.equals("泰山石膏")){
                            newSgbzl = purchaseUtil.gypsumBoardCategory(wlfl, wlmc, xl, pp, zl);
                        }
                        newSgbhd = purchaseUtil.extractThickness(gg);
                        bo.set("SGBZL", newSgbzl);
                        bo.set("SGBHD", newSgbhd);
                    }
                    bos.add(bo);
                }

                SDK.getBOAPI().createDataBO(hzb, bos, UserContext.fromUID("admin"));
                LOGGER.info("已迁移{}条数据到汇总表（页号: {}，时间范围: {} - {}）",
                        bos.size(), pageNo, startDate, endDate);

                hasMore = pageData.size() == PAGE_SIZE;
                pageNo++;
            } while (hasMore);
            if (hzb.equals("BO_EU_BNBM_SCRK_HZ")) {
                int update = DBSql.update("UPDATE BO_EU_BNBM_SCRK_HZ a" +
                        " LEFT JOIN BO_EU_DATALINKUP_ZBXS b ON a.SGBZL = b.TYPE AND a.SGBHD = b.THICKNESS" +
                        " SET a.ZBCL = a.RKSL * b.ZBXS" +
                        " WHERE a.BKGS = '泰山石膏' " +
                        "  AND a.WLMC LIKE '%石膏板%' " +
                        "  AND a.RKRQ >= '" + startDate + "'");
                LOGGER.info("更新折标产量条数：{}-开始时间为：{}", update, startDate);
            }
        }catch (Exception e){
            LOGGER.error("汇总数据失败 [汇总表={}, 第几页={}]: {}",
                    hzb, PAGE_SIZE, e.getMessage(), e);
        }
    }

    @Override
    public void summarizeScopeDataYs(String targetTable, Date startDated, Date endDated, String targetTimeField, String hzb) {

    }

    @Override
    public void querySourceDataYS(String ccId, String tableName, String timeField, Date startDate, Date endDate, String partitionField, List<BO> fieldMappings, String targetTable, String jezd) {

    }
}
