package com.awspaas.user.apps.bnbm.datalinkup.job;

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.commons.database.RowMap;
import com.actionsoft.bpms.schedule.IJob;
import com.actionsoft.bpms.server.UserContext;
import com.actionsoft.bpms.util.DBSql;
import com.actionsoft.sdk.local.SDK;
import com.awspaas.user.apps.bnbm.datalinkup.enums.Section;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName: WaterproofPaintAccountsReceivableJob
 * @Description: 防水涂料计算应收单 - 优化版本（批量处理提升性能）
 * @date: 2025/8/29 16:38
 */
public class WaterproofPaintAccountsReceivableJob implements IJob {
    private static final Logger LOGGER = LoggerFactory.getLogger(WaterproofPaintAccountsReceivableJob.class);

    // 定义常量
    private static final String RDS_ID = "e19d738a-8eac-4c42-9c08-7fe93e75638d";
    private static final int BATCH_SIZE = 1000;
    private static final int CUSTOMER_BATCH_SIZE = 500; // 客户分批大小

    @Override
    public void execute(JobExecutionContext job) throws JobExecutionException {
        try {
            String param = SDK.getJobAPI().getJobParameter(job);
            int timeRange = StringUtils.isNotBlank(param) ? Integer.parseInt(param) : 0;

            // 获取当前时间
            LocalDate nowDate = LocalDate.now();
            LocalDate startDate;
            if (timeRange > 0) {
                startDate = nowDate.minusDays(timeRange);
            } else {
                // 默认计算去年第一天到现在的数据
                startDate = nowDate.minusYears(1).withDayOfYear(1);
            }

            LOGGER.info("开始执行防水涂料应收单计算任务，时间范围：{} 到 {}", startDate, nowDate);

            // 依次处理防水和涂料两个板块
            boolean allSuccess = true;
            for (Section section : Section.values()) {
                boolean success = processSectionOptimized(section, startDate, nowDate);
                if (!success) {
                    allSuccess = false;
                    LOGGER.error("{}板块处理失败", section.getName());
                }
            }

            if (!allSuccess) {
                throw new JobExecutionException("部分板块处理失败");
            }
            LOGGER.info("防水涂料应收单计算任务完成");

        } catch (Exception e) {
            LOGGER.error("执行防水涂料应收单计算任务时发生错误", e);
            throw new JobExecutionException("任务执行失败", e);
        }
    }

    /**
     * 优化后的板块数据处理方法
     */
    private boolean processSectionOptimized(Section section, LocalDate startDate, LocalDate endDate) {
        String sectionName = section.getName();
        LOGGER.info("开始处理{}板块数据，时间范围：{} 到 {}", sectionName, startDate, endDate);

        try {
            // 清理目标表数据
            String startDateFormat = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 00:00:00";
            int deleteCount = DBSql.update("DELETE FROM " + section.getTargetTable() + " WHERE RQ >= ?", new String[]{startDateFormat});
            LOGGER.info("已删除目标表[{}]中{}条数据", section.getTargetTable(), deleteCount);

            // 获取所有销售组织-客户组合
            String bkgs = section.getBkgs();
            String sql =  "SELECT QYGS, FCUSTNAME, SQ AS FPROVINCE, CS AS FCITY, QY AS FDISTRICT, XSZZ " +
                    " FROM " + section.getYsdTable() + " WHERE QYGS IS NOT NULL AND FCUSTNAME IS NOT NULL GROUP BY FCUSTNAME,XSZZ";
//            if (bkgs.equals("北新防水")){
//                sql += " AND XSZZ !='北新防水工程（辽宁）有限公司' " +
//                        "AND XSZZ != '北新防水工程（四川）有限公司' AND F_SFNBJY ='是'";
//            }else {
//                sql += " AND F_SFNBJY ='是'";
//            }
            List<RowMap> customerMaps = DBSql.getMaps(sql);

            if (customerMaps == null || customerMaps.isEmpty()) {
                LOGGER.warn("{}板块未查询到销售组织和客户数据", sectionName);
                return true;
            }

            LOGGER.info("{}板块共查询到 {} 个销售组织-客户组合", sectionName, customerMaps.size());

            // 分批次处理客户数据
            int totalCustomers = customerMaps.size();
            for (int i = 0; i < totalCustomers; i += CUSTOMER_BATCH_SIZE) {
                int endIndex = Math.min(i + CUSTOMER_BATCH_SIZE, totalCustomers);
                List<RowMap> batchCustomers = customerMaps.subList(i, endIndex);

                LOGGER.info("{}板块正在处理第 {} 批客户，进度: {}/{}",
                        sectionName, (i / CUSTOMER_BATCH_SIZE) + 1, endIndex, totalCustomers);

                boolean batchSuccess = processCustomerBatch(section, batchCustomers, startDate, endDate);
                if (!batchSuccess) {
                    LOGGER.error("{}板块第 {} 批客户处理失败", sectionName, (i / CUSTOMER_BATCH_SIZE) + 1);
                    return false;
                }
            }

            LOGGER.info("{}板块数据处理完成，共处理 {} 个客户组合", sectionName, totalCustomers);
            return true;

        } catch (Exception e) {
            LOGGER.error("处理{}板块数据时发生错误", sectionName, e);
            return false;
        }
    }

    /**
     * 处理一批客户数据
     */
    private boolean processCustomerBatch(Section section, List<RowMap> customerBatch,
                                         LocalDate startDate, LocalDate endDate) {
        try {
            // 提取销售组织和客户名称列表
            List<String> saleOrgUnits = customerBatch.stream()
                    .map(row -> row.getString("XSZZ"))
                    .distinct()
                    .collect(Collectors.toList());

            List<String> custNames = customerBatch.stream()
                    .map(row -> row.getString("FCUSTNAME"))
                    .distinct()
                    .collect(Collectors.toList());

            // 获取需要处理的所有月末日期
            List<LocalDate> monthEndDates = getMonthEndDates(startDate, endDate);
            LOGGER.info("查看时间范围：{}",Arrays.toString(monthEndDates.toArray()));

            // 批量预加载所有需要的数据
            Map<String, BigDecimal> preloadedResults = preloadAllData(
                    section, saleOrgUnits, custNames, monthEndDates);

            // 批量处理数据
            List<BO> allRecords = new ArrayList<>();

            for (LocalDate monthEndDate : monthEndDates) {
                for (RowMap customer : customerBatch) {
                    String saleOrgUnit = customer.getString("XSZZ");
                    String custName = customer.getString("FCUSTNAME");
                    String keyPrefix = saleOrgUnit + "_" + custName + "_";
//                    LOGGER.info("客户、销售组织：{}",keyPrefix);

                    try {
                        // 从预加载数据中获取计算结果
                        BigDecimal qcye = getPreloadedValue(preloadedResults, keyPrefix + "QCYE_" + monthEndDate);
//                        LOGGER.info("计算出来的期初余额：{}",qcye.doubleValue());
                        BigDecimal ljxs = getPreloadedValue(preloadedResults, keyPrefix + "LJXS_" + monthEndDate);
//                        LOGGER.info("计算出来的累计销售：{}",ljxs.doubleValue());
                        BigDecimal ljhk = getPreloadedValue(preloadedResults, keyPrefix + "LJHK_" + monthEndDate);
//                        LOGGER.info("计算出来的累计还款：{}",ljhk.doubleValue());
                        BigDecimal ysye = qcye.add(ljxs).subtract(ljhk);
//                        LOGGER.info("计算出来的应收余额：{}",ysye.doubleValue());

                        // 从预加载数据中获取账龄分析
                        Map<String, BigDecimal> zlfx = new HashMap<>();
                        for (String zlfxKey : Arrays.asList("ZLFX0_60", "ZLFX60_1", "ZLFX1_2", "ZLFX2_3", "ZLFX3_4", "ZLFX4_5", "ZLFX5")) {
                            BigDecimal value = getPreloadedValue(preloadedResults, keyPrefix + zlfxKey + "_" + monthEndDate);
                            zlfx.put(zlfxKey, value);
                        }

                        // 创建记录
                        BO record = createRecord(
                                section,
                                customer.getString("QYGS"),
                                saleOrgUnit,
                                monthEndDate,
                                custName,
                                customer.getString("FPROVINCE"),
                                customer.getString("FCITY"),
                                customer.getString("FDISTRICT") != null ? customer.getString("FDISTRICT") : "",
                                qcye, ljxs, ljhk, ysye, zlfx
                        );

                        allRecords.add(record);

                    } catch (Exception e) {
                        LOGGER.error("处理客户数据时发生错误，销售组织: {}, 客户: {}, 日期: {}",
                                saleOrgUnit, custName, monthEndDate, e);
                    }
                }
            }

            // 分批插入数据
            for (int i = 0; i < allRecords.size(); i += BATCH_SIZE) {
                int endIndex = Math.min(i + BATCH_SIZE, allRecords.size());
                List<BO> batchRecords = allRecords.subList(i, endIndex);
                batchInsert(section, batchRecords);
            }

            return true;

        } catch (Exception e) {
            LOGGER.error("处理客户批次数据时发生错误", e);
            return false;
        }
    }

    /**
     * 安全获取预加载值
     */
    private BigDecimal getPreloadedValue(Map<String, BigDecimal> preloadedData, String key) {
        return preloadedData.getOrDefault(key, BigDecimal.ZERO);
    }

    /**
     * 预加载所有需要的数据
     */
    private Map<String, BigDecimal> preloadAllData(Section section,
                                                   List<String> saleOrgUnits, List<String> custNames, List<LocalDate> monthEndDates) {

        Map<String, BigDecimal> results = new HashMap<>();

        try {
            // 扩展日期范围：包含去年完整数据和当前时间范围
            LocalDate extendedStartDate = monthEndDates.get(0).minusYears(1).withDayOfYear(1);
            LocalDate extendedEndDate = monthEndDates.get(monthEndDates.size() - 1);
            String format = extendedStartDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            String format2 = extendedEndDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            LOGGER.info("format:{};format2:{}",format,format2);
            List<LocalDate> extendedMonthEndDates = getMonthEndDates(extendedStartDate, extendedEndDate);
            // 批量查询应收单数据
            Map<String, BigDecimal> ysData = batchQueryYSDData(section, saleOrgUnits, custNames, extendedMonthEndDates);
            // 批量查询收款单数据
            Map<String, BigDecimal> skData = batchQuerySKDData(section, saleOrgUnits, custNames, extendedMonthEndDates);
            // 批量查询收款退款单数据
            Map<String, BigDecimal> sktkData = batchQuerySKTKDData(section, saleOrgUnits, custNames, extendedMonthEndDates);
            // 批量查询历史余额数据
            Map<String, BigDecimal> historyData = batchQueryHistoryBalance(section, saleOrgUnits, custNames, extendedMonthEndDates);
            // 计算所有需要的指标
            calculateAllMetrics(results, ysData, skData, sktkData, historyData, saleOrgUnits, custNames, monthEndDates,extendedMonthEndDates);
        } catch (Exception e) {
            LOGGER.error("预加载数据时发生错误", e);
        }

        return results;
    }

    /**
     * 批量查询应收单数据
     */
    private Map<String, BigDecimal> batchQueryYSDData(Section section, List<String> saleOrgUnits,
                                                      List<String> custNames, List<LocalDate> monthEndDates) {

        Map<String, BigDecimal> result = new HashMap<>();

        if (saleOrgUnits.isEmpty() || custNames.isEmpty() || monthEndDates.isEmpty()) {
            return result;
        }

        try {
            String inSaleOrgs = buildInCondition(saleOrgUnits);
            String inCustNames = buildInCondition(custNames);

            // 构建日期条件
            StringBuilder dateCondition = new StringBuilder();
            dateCondition.append("DZRQ >= '")
                    .append(monthEndDates.get(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 00:00:00' AND DZRQ <= '")
                    .append(monthEndDates.get(monthEndDates.size()-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 23:59:59'");
//            for (LocalDate date : monthEndDates) {
//                LocalDate monthStart = date.withDayOfMonth(1);
//                if (dateCondition.length() > 0) {
//                    dateCondition.append(" OR ");
//                }
//                dateCondition.append("(DZRQ >= '")
//                        .append(monthStart.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 00:00:00' AND DZRQ <= '")
//                        .append(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 23:59:59')");
//            }

            String bkgs = section.getBkgs();
            String sql = "SELECT XSZZ, FCUSTNAME, DATE_FORMAT(DZRQ, '%Y-%m-%d') as BILL_DATE, SUM(SSJERMB) as TOTAL " +
                    "FROM " + section.getYsdTable() +
                    " WHERE XSZZ IN (" + inSaleOrgs + ") " +
                    " AND FCUSTNAME IN (" + inCustNames + ") " +
                    " AND (" + dateCondition + ") ";
            if (bkgs.equals("北新防水")){
                sql += " AND XSZZ !='北新防水工程（辽宁）有限公司' " +
                        "AND XSZZ != '北新防水工程（四川）有限公司' AND F_SFNBJY ='是'";
            }else {
                sql += " AND F_SFNBJY ='是'";
            }
            sql += " GROUP BY XSZZ, FCUSTNAME, DATE_FORMAT(DZRQ, '%Y-%m-%d')";
//            LOGGER.info("应收单数据sql = " + sql);
            List<RowMap> queryResults = DBSql.getMaps(sql);

            for (RowMap row : queryResults) {
                String key = row.getString("XSZZ") + "_" + row.getString("FCUSTNAME") + "_" + row.getString("BILL_DATE");
                BigDecimal value = row.get("TOTAL") != null ? new BigDecimal(row.get("TOTAL").toString()) : BigDecimal.ZERO;
                result.put(key, value);
            }

        } catch (Exception e) {
            LOGGER.error("批量查询应收单数据时发生错误", e);
        }

        return result;
    }

    /**
     * 批量查询收款单数据
     */
    private Map<String, BigDecimal> batchQuerySKDData(Section section, List<String> saleOrgUnits,
                                                      List<String> custNames, List<LocalDate> monthEndDates) {

        Map<String, BigDecimal> result = new HashMap<>();

        try {
            String inSaleOrgs = buildInCondition(saleOrgUnits);
            String inCustNames = buildInCondition(custNames);

            StringBuilder dateCondition = new StringBuilder();
            dateCondition.append("FBILLDATE >= '")
                    .append(monthEndDates.get(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 00:00:00' AND FBILLDATE <= '")
                    .append(monthEndDates.get(monthEndDates.size()-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 23:59:59'");
//            for (LocalDate date : monthEndDates) {
//                LocalDate monthStart = date.withDayOfMonth(1);
//                if (dateCondition.length() > 0) {
//                    dateCondition.append(" OR ");
//                }
//                dateCondition.append("(DZRQ >= '")
//                        .append(monthStart.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 00:00:00' AND DZRQ <= '")
//                        .append(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 23:59:59')");
//            }

            String bkgs = section.getBkgs();
            String sql = "SELECT FSALEORGUNIT, FCUSTNAME, DATE_FORMAT(FBILLDATE, '%Y-%m-%d') as BILL_DATE, SUM(FSALEAMOUNTRMB) as TOTAL " +
                    "FROM " + section.getSkdTable() +
                    " WHERE FSALEORGUNIT IN (" + inSaleOrgs + ") " +
                    " AND FCUSTNAME IN (" + inCustNames + ") " +
                    " AND (" + dateCondition + ") ";
            if (bkgs.equals("北新防水")){
                sql += " AND FSALEORGUNIT !='北新防水工程（辽宁）有限公司' " +
                        "AND FSALEORGUNIT != '北新防水工程（四川）有限公司' AND F_SFNBJY ='是'";
            }else {
                sql += " AND F_SFNBJY ='是'";
            }
            sql += " GROUP BY FSALEORGUNIT, FCUSTNAME, DATE_FORMAT(FBILLDATE, '%Y-%m-%d')";

//            LOGGER.info("收款单数据sql = " + sql);
            List<RowMap> queryResults = DBSql.getMaps(sql);

            for (RowMap row : queryResults) {
                String key = row.getString("FSALEORGUNIT") + "_" + row.getString("FCUSTNAME") + "_" + row.getString("BILL_DATE");
                BigDecimal value = row.get("TOTAL") != null ? new BigDecimal(row.get("TOTAL").toString()) : BigDecimal.ZERO;
                result.put(key, value);
            }

        } catch (Exception e) {
            LOGGER.error("批量查询收款单数据时发生错误", e);
        }

        return result;
    }

    /**
     * 批量查询收款退款单数据
     */
    private Map<String, BigDecimal> batchQuerySKTKDData(Section section, List<String> saleOrgUnits,
                                                        List<String> custNames, List<LocalDate> monthEndDates) {

        Map<String, BigDecimal> result = new HashMap<>();

        try {
            String inSaleOrgs = buildInCondition(saleOrgUnits);
            String inCustNames = buildInCondition(custNames);

            StringBuilder dateCondition = new StringBuilder();
            dateCondition.append("FBILLDATE >= '")
                    .append(monthEndDates.get(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 00:00:00' AND FBILLDATE <= '")
                    .append(monthEndDates.get(monthEndDates.size()-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).append(" 23:59:59'");
//            for (LocalDate date : monthEndDates) {
//                LocalDate monthStart = date.withDayOfMonth(1);
//                if (dateCondition.length() > 0) {
//                    dateCondition.append(" OR ");
//                }
//                dateCondition.append("(DZRQ >= '")
//                        .append(monthStart.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 00:00:00' AND DZRQ <= '")
//                        .append(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
//                        .append(" 23:59:59')");
//            }

            String bkgs = section.getBkgs();
            String sql = "SELECT FSALEORGUNIT, FCUSTNAME, DATE_FORMAT(FBILLDATE, '%Y-%m-%d') as BILL_DATE, SUM(FSALEAMOUNTRMB) as TOTAL " +
                    "FROM " + section.getSktkdTable() +
                    " WHERE FSALEORGUNIT IN (" + inSaleOrgs + ") " +
                    " AND FCUSTNAME IN (" + inCustNames + ") " +
                    " AND (" + dateCondition + ") ";
            if (bkgs.equals("北新防水")){
                sql += " AND FSALEORGUNIT !='北新防水工程（辽宁）有限公司' " +
                        "AND FSALEORGUNIT != '北新防水工程（四川）有限公司' AND F_SFNBJY ='是'";
            }else {
                sql += " AND F_SFNBJY ='是'";
            }
            sql += " GROUP BY FSALEORGUNIT, FCUSTNAME, DATE_FORMAT(FBILLDATE, '%Y-%m-%d')";

//            LOGGER.info("收款退款单数据sql = " + sql);
            List<RowMap> queryResults = DBSql.getMaps(sql);

            for (RowMap row : queryResults) {
                String key = row.getString("FSALEORGUNIT") + "_" + row.getString("FCUSTNAME") + "_" + row.getString("BILL_DATE");
                BigDecimal value = row.get("TOTAL") != null ? new BigDecimal(row.get("TOTAL").toString()) : BigDecimal.ZERO;
                result.put(key, value);
            }

        } catch (Exception e) {
            LOGGER.error("批量查询收款退款单数据时发生错误", e);
        }

        return result;
    }

    /**
     * 批量查询历史余额数据
     */
    private Map<String, BigDecimal> batchQueryHistoryBalance(Section section, List<String> saleOrgUnits,
                                                             List<String> custNames, List<LocalDate> monthEndDates) {

        Map<String, BigDecimal> result = new HashMap<>();

        try {
            String inSaleOrgs = buildInCondition(saleOrgUnits);
            String inCustNames = buildInCondition(custNames);
            String inDates = monthEndDates.stream()
                    .map(date -> "'" + date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 23:59:59'")
                    .collect(Collectors.joining(","));

            String sql = "SELECT XSZZ, KH, DATE_FORMAT(RQ, '%Y-%m-%d') as BALANCE_DATE, YSYE " +
                    "FROM " + section.getTargetTable() +
                    " WHERE XSZZ IN (" + inSaleOrgs + ") " +
                    " AND KH IN (" + inCustNames + ") " +
                    " AND RQ IN (" + inDates + ")";

//            LOGGER.info("历史余额数据sql = " + sql);
            List<RowMap> queryResults = DBSql.getMaps(sql);

            for (RowMap row : queryResults) {
                String key = row.getString("XSZZ") + "_" + row.getString("KH") + "_" + row.getString("BALANCE_DATE");
                BigDecimal value = row.get("YSYE") != null ? new BigDecimal(row.get("YSYE").toString()) : BigDecimal.ZERO;
                result.put(key, value);
            }

        } catch (Exception e) {
            LOGGER.error("批量查询历史余额数据时发生错误", e);
        }

        return result;
    }

    /**
     * 计算所有指标
     */
    private void calculateAllMetrics(Map<String, BigDecimal> results,
                                     Map<String, BigDecimal> ysData, Map<String, BigDecimal> skData,
                                     Map<String, BigDecimal> sktkData, Map<String, BigDecimal> historyData,
                                     List<String> saleOrgUnits, List<String> custNames, List<LocalDate> monthEndDates,
                                     List<LocalDate> extendedMonthEndDates) {

        // 计算每个客户每个月的指标
        for (String saleOrgUnit : saleOrgUnits) {
            for (String custName : custNames) {
                String keyPrefix = saleOrgUnit + "_" + custName + "_";

                for (LocalDate monthEndDate : monthEndDates) {
                    String dateKey = monthEndDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    String fullKeyPrefix = keyPrefix + dateKey;

                    try {
                        // 计算期初余额（上一年度末余额）
                        LocalDate previousYearEnd = monthEndDate.minusYears(1).withDayOfYear(monthEndDate.minusYears(1).lengthOfYear());
                        BigDecimal qcye = calculatePeriodBalance(ysData, skData, sktkData, saleOrgUnit, custName, previousYearEnd.withDayOfYear(1), previousYearEnd);

                        // 计算累计销售（本年年初到当前月末）
                        LocalDate yearStart = monthEndDate.withDayOfYear(1);
                        BigDecimal ljxs = calculatePeriodBalance(ysData, null, null, saleOrgUnit, custName, yearStart, monthEndDate);

                        // 计算累计还款（本年年初到当前月末）
                        BigDecimal ljhk = calculatePeriodBalance(null, skData, sktkData, saleOrgUnit, custName, yearStart, monthEndDate);

                        // 计算应收余额
                        BigDecimal ysye = qcye.add(ljxs).subtract(ljhk);

                        // 计算账龄分析
                        Map<String, BigDecimal> zlfx = calculateAgingAnalysis(historyData, saleOrgUnit, custName, monthEndDate, ysye);

                        // 存储计算结果
                        results.put(keyPrefix + "QCYE_" + monthEndDate, qcye);
                        results.put(keyPrefix + "LJXS_" + monthEndDate, ljxs);
                        results.put(keyPrefix + "LJHK_" + monthEndDate, ljhk);
                        results.put(keyPrefix + "YSYE_" + monthEndDate, ysye);
//                      LOGGER.info("计算{}：{}",keyPrefix + "QCYE_" + monthEndDate,qcye);
//                      LOGGER.info("计算{}：{}",keyPrefix + "LJXS_" + monthEndDate, ljxs);
//                      LOGGER.info("计算{}：{}",keyPrefix + "LJHK_" + monthEndDate, ljhk);
//                      LOGGER.info("计算{}：{}",keyPrefix + "YSYE_" + monthEndDate, ysye);

                        for (Map.Entry<String, BigDecimal> entry : zlfx.entrySet()) {
                            results.put(keyPrefix + entry.getKey() + "_" + monthEndDate, entry.getValue());
                        }
                    } catch (Exception e) {
                        LOGGER.error("计算指标时发生错误，销售组织: {}, 客户: {}, 日期: {}",
                                saleOrgUnit, custName, monthEndDate, e);
                    }
                }
            }
        }
    }

    /**
     * 计算指定时间段的余额
     */
    private BigDecimal calculatePeriodBalance(Map<String, BigDecimal> ysData, Map<String, BigDecimal> skData,
                                              Map<String, BigDecimal> sktkData, String saleOrgUnit, String custName,
                                              LocalDate startDate, LocalDate endDate) {

        BigDecimal result = BigDecimal.ZERO;
        String keyPrefix = saleOrgUnit + "_" + custName + "_";

        // 累加指定时间段内的数据
        LocalDate current = startDate;
        while (!current.isAfter(endDate)) {
            String dateKey = current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            String fullKey = keyPrefix + dateKey;

            if (ysData != null) {
                result = result.add(ysData.getOrDefault(fullKey, BigDecimal.ZERO));
            }

            if (skData != null) {
                result = result.subtract(skData.getOrDefault(fullKey, BigDecimal.ZERO));
            }

            if (sktkData != null) {
                result = result.add(sktkData.getOrDefault(fullKey, BigDecimal.ZERO));
            }

            current = current.plusDays(1);
        }

        return result;
    }

    /**
     * 计算账龄分析
     */
    private Map<String, BigDecimal> calculateAgingAnalysis(Map<String, BigDecimal> historyData,
                                                           String saleOrgUnit, String custName, LocalDate currentDate, BigDecimal currentBalance) {

        Map<String, BigDecimal> result = new HashMap<>();
        String keyPrefix = saleOrgUnit + "_" + custName + "_";

        try {
            // 计算各个时间点的历史余额
            LocalDate date60DaysAgo = currentDate.minusDays(60);
            LocalDate date1YearAgo = currentDate.minusYears(1);
            LocalDate date2YearsAgo = currentDate.minusYears(2);
            LocalDate date3YearsAgo = currentDate.minusYears(3);
            LocalDate date4YearsAgo = currentDate.minusYears(4);
            LocalDate date5YearsAgo = currentDate.minusYears(5);

            // 查找历史余额
            BigDecimal balance60DaysAgo = findHistoricalBalance(historyData, keyPrefix, date60DaysAgo);
            BigDecimal balance1YearAgo = findHistoricalBalance(historyData, keyPrefix, date1YearAgo);
            BigDecimal balance2YearsAgo = findHistoricalBalance(historyData, keyPrefix, date2YearsAgo);
            BigDecimal balance3YearsAgo = findHistoricalBalance(historyData, keyPrefix, date3YearsAgo);
            BigDecimal balance4YearsAgo = findHistoricalBalance(historyData, keyPrefix, date4YearsAgo);
            BigDecimal balance5YearsAgo = findHistoricalBalance(historyData, keyPrefix, date5YearsAgo);

            // 计算各账龄段金额
            result.put("ZLFX0_60", currentBalance.subtract(balance60DaysAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX60_1", balance60DaysAgo.subtract(balance1YearAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX1_2", balance1YearAgo.subtract(balance2YearsAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX2_3", balance2YearsAgo.subtract(balance3YearsAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX3_4", balance3YearsAgo.subtract(balance4YearsAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX4_5", balance4YearsAgo.subtract(balance5YearsAgo.max(BigDecimal.ZERO)));
            result.put("ZLFX5", balance5YearsAgo.max(BigDecimal.ZERO));

        } catch (Exception e) {
            LOGGER.error("计算账龄分析时发生错误，销售组织: {}, 客户: {}", saleOrgUnit, custName, e);
            // 设置默认值
            result.put("ZLFX0_60", BigDecimal.ZERO);
            result.put("ZLFX60_1", BigDecimal.ZERO);
            result.put("ZLFX1_2", BigDecimal.ZERO);
            result.put("ZLFX2_3", BigDecimal.ZERO);
            result.put("ZLFX3_4", BigDecimal.ZERO);
            result.put("ZLFX4_5", BigDecimal.ZERO);
            result.put("ZLFX5", BigDecimal.ZERO);
        }

        return result;
    }

    /**
     * 查找历史余额
     */
    private BigDecimal findHistoricalBalance(Map<String, BigDecimal> historyData, String keyPrefix, LocalDate targetDate) {
        // 调整为目标月份的月末日期
        LocalDate monthEndDate = targetDate.withDayOfMonth(targetDate.lengthOfMonth());
        String dateKey = monthEndDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String fullKey = keyPrefix + dateKey;

        return historyData.getOrDefault(fullKey, BigDecimal.ZERO);
    }

    /**
     * 构建IN查询条件
     */
    private String buildInCondition(List<String> values) {
        if (values == null || values.isEmpty()) {
            return "''";
        }
        return values.stream()
                .map(value -> "'" + value.replace("'", "''") + "'")
                .collect(Collectors.joining(","));
    }

    /**
     * 获取时间范围内的所有月末日期（优化版）
     */
    private List<LocalDate> getMonthEndDates(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> monthEndDates = new ArrayList<>();
        LocalDate current = startDate.withDayOfMonth(1);

        while (!current.isAfter(endDate)) {
            if (current.getYear() == endDate.getYear() && current.getMonth() == endDate.getMonth()) {
                // 当前月份与结束日期同年同月，使用结束日期前一天
                LocalDate dayBeforeEnd = endDate.minusDays(1);
                if (!dayBeforeEnd.isBefore(startDate)) {
                    monthEndDates.add(dayBeforeEnd);
                }
                break;
            } else {
                // 其他月份使用月末日期
                LocalDate monthEnd = current.withDayOfMonth(current.lengthOfMonth());
                if (!monthEnd.isBefore(startDate) && !monthEnd.isAfter(endDate)) {
                    monthEndDates.add(monthEnd);
                }
            }
            current = current.plusMonths(1);
        }

        return monthEndDates;
    }

    /**
     * 创建数据记录
     */
    private BO createRecord(Section section, String manageRegionName, String saleOrgUnit, LocalDate date,
                            String custName, String province, String city, String district,
                            BigDecimal qcye, BigDecimal ljxs, BigDecimal ljhk, BigDecimal ysye,
                            Map<String, BigDecimal> zlfx) {
        BO record = new BO();

        // 业务字段
        record.set("BKGS", section.getBkgs());
        record.set("QYGS", manageRegionName);
        record.set("XSZZ", saleOrgUnit);
        record.set("RQ", Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
        record.set("KH", custName);
        record.set("SHENGQU", province);
        record.set("SHIQU", city);
        record.set("QX", district);
        record.set("QCYE", qcye);
        record.set("LJXS", ljxs);
        record.set("LJHK", ljhk);
        record.set("YSYE", ysye);

        // 账龄分析字段
        record.set("ZLFX0_60", zlfx.getOrDefault("ZLFX0_60", BigDecimal.ZERO));
        record.set("ZLFX60_1", zlfx.getOrDefault("ZLFX60_1", BigDecimal.ZERO));
        record.set("ZLFX1_2", zlfx.getOrDefault("ZLFX1_2", BigDecimal.ZERO));
        record.set("ZLFX2_3", zlfx.getOrDefault("ZLFX2_3", BigDecimal.ZERO));
        record.set("ZLFX3_4", zlfx.getOrDefault("ZLFX3_4", BigDecimal.ZERO));
        record.set("ZLFX4_5", zlfx.getOrDefault("ZLFX4_5", BigDecimal.ZERO));
        record.set("ZLFX5", zlfx.getOrDefault("ZLFX5", BigDecimal.ZERO));

        return record;
    }

    /**
     * 批量插入数据
     */
    private void batchInsert(Section section, List<BO> batchData) {
        try {
            int[] results = SDK.getBOAPI().createDataBO(section.getTargetTable(), batchData, UserContext.fromUID("admin"));
            LOGGER.info("成功插入 {} 条数据到 {} 表", batchData.size(), section.getTargetTable());
        } catch (Exception e) {
            LOGGER.error("批量插入{}板块数据到表{}时发生错误", section.getName(), section.getTargetTable(), e);
        }
    }
}