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

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.commons.database.RowMap;
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.entity.DateRange;
import com.awspaas.user.apps.bnbm.datalinkup.entity.Location;
import com.awspaas.user.apps.bnbm.datalinkup.service.DataSummaryService;
import com.awspaas.user.apps.bnbm.datalinkup.util.SaleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Array;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 销售汇总维度
 */
public class SaleCountDimensionImpl implements DataSummaryService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SaleCountDimensionImpl.class);
    // 维度表名常量
    /**
     * 销售_营业收入_年月
     */
    private static final String BO_EU_XS_YESR = "BO_EU_XS_YESR";
    /**
     * 销售_销量销额_年月
     */
    private static final String BO_EU_XS_XLXE = "BO_EU_XS_XLXE";
    /**
     * 销售_应收账款_年月
     */
    private static final String BO_EU_XS_YSZK = "BO_EU_XS_YSZK";
    /**
     * 销售_区域两金占比_年月
     */
    private static final String BO_EU_XS_QYLJZB = "BO_EU_XS_QYLJZB";

    // 原始数据表名
    /**
     * 销售_销售类_汇总表
     */
    private static final String SALES_DETAIL_TABLE = "BO_EU_BNBM_DATALINKUP_XS_XSL_HZ";
    /**
     * 销售_应收类_汇总
     */
    private static final String RECEIVABLE_DETAIL_TABLE = "BO_EU_BNBM_DATALINKUP_XS_YSL";
    /**
     * 采购_库存_汇总
     */
    private static final String BO_EU_DWD_ORDER_KC_HZ = "BO_EU_DWD_ORDER_KC_HZ";

    // 日期格式化
    private static final SimpleDateFormat YEAR_MONTH_FORMAT = new SimpleDateFormat("yyyy-MM");
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    // 批量处理大小
    private static final int BATCH_SIZE = 1000;
    // 批量分页大小
    private static final int PAGE_SIZE = 1000;

    @Override
    public void calculateSummary(DateRange dateRange, BO mainConfig) {
//        LOGGER.info("dateRange:{},mainConfig：{}",dateRange,mainConfig.toJSONObject().toJSONString());
        try {
            // 从主配置获取BKGS值
            String bkgs = mainConfig.getString("BKGS");
            if (bkgs == null || bkgs.isEmpty()) {
                LOGGER.error("主配置中BKGS为空，无法进行汇总计算");
                return;
            }
            if (dateRange == null || dateRange.getStartDate() == null || dateRange.getEndDate() == null) {
                LOGGER.info("未提供有效时间范围，按当前日期计算");
                Calendar cal = Calendar.getInstance();
//                DateRange dateRangeNow = new DateRange();

                // 设置为当前月的第一天
                cal.set(Calendar.DAY_OF_MONTH, 1);
                dateRange.setStartDate(cal.getTime());

                // 设置为当前月的最后一天
                cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
                dateRange.setEndDate(cal.getTime());

                // 处理营业收入数据
                newProcessRevenueData(dateRange,bkgs);
                // 处理销量销额数据（分页查询）
                newProcessSalesVolumeData(dateRange,bkgs);
                // 区域两金占比
                newProcessRegionTwoFundsRatio(dateRange,bkgs);
                // 处理应收账款数据（分页查询）
                newprocessReceivableData(dateRange, bkgs);

                LOGGER.info("{}销售数据多维度汇总计算完成",bkgs);
            } else {
                LOGGER.info("开始执行销售数据多维度汇总计算（时间范围: {} 至 {})",
                        dateRange.getStartDate(), dateRange.getEndDate());

                // 处理营业收入数据
                newProcessRevenueData(dateRange,bkgs);
                // 处理销量销额数据（分页查询）
                newProcessSalesVolumeData(dateRange,bkgs);
                // 区域两金占比
                newProcessRegionTwoFundsRatio(dateRange,bkgs);
                // 处理应收账款数据（分页查询）
                newprocessReceivableData(dateRange, bkgs);

                LOGGER.info("{}销售数据多维度汇总计算完成",bkgs);
            }
        } catch (Exception e) {
            String errorMsg = "销售数据汇总计算失败: " + e.getMessage();
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    private void newprocessReceivableData(DateRange dateRange, String bkgs) {
        LOGGER.info("开始处理应收账款数据，开始时间: {}, 板块公司: {}", dateRange.getStartDate(), bkgs);
        int totalCount = 0;

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_YSZK + " WHERE YEARMONTH >= ? AND BKGS = ?";
        try {
            LOGGER.info("应收账款删除sql{}",deleteSql);
            int deleted = DBSql.update(deleteSql, new Object[]{YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs});
            LOGGER.info("应收账款-已删除{}-{}条应收账款记录\nsql为：{}", YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), deleted,deleteSql);
        } catch (Exception e) {
            LOGGER.error("应收账款-删除{}数据错误，删除sql为：{}，请检查数据库链接：{}", bkgs, deleteSql, e.getMessage());
            throw e;
        }
        // 获取公司简称
        List<RowMap> gsjcList = DBSql.getMaps("SELECT GSMC,JC FROM BO_EU_BNBM_ZZWHB");
        Map<String, String> gsjcMap = gsjcList.stream()
                .filter(row -> {
                    String gsmc = row.getString("GSMC");
                    String jc = row.getString("JC");
                    return gsmc != null && jc != null;
                })
                .collect(Collectors.toMap(
                        row -> row.getString("GSMC"),
                        row -> row.getString("JC"),
                        (existing, replacement) -> existing // 处理重复key
                ));

        String sql = "SELECT t.RQ AS RQ,t.QYGS AS QYGS,t.XSZZ AS XSZZ,t.SHENGQU AS SHENGQU,t.SHIQU AS SHIQU," +
                " t.QX AS QX,t.QCYE AS QCYE,t.LJXS AS LJXS,t.LJHK AS LJHK,t.YSYE AS YSYE," +
                "    t.ZLFX0_60 AS ZLFX0_60,t.ZLFX60_1 AS ZLFX60_1,t.ZLFX1_2 AS ZLFX1_2,t.ZLFX2_3 AS ZLFX2_3," +
                " t.ZLFX3_4 AS ZLFX3_4,t.ZLFX4_5 AS ZLFX4_5,t.ZLFX5 AS ZLFX5" +
                " FROM BO_EU_BNBM_DATALINKUP_XS_YSL t" +
                " INNER JOIN (" +
                "    SELECT MAX(RQ) AS MaxRQ,YEAR(RQ) AS Year,MONTH(RQ) AS Month" +
                "    FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
                "    WHERE DATE(RQ) >= ? AND BKGS = ?" +
                "    GROUP BY YEAR(RQ), MONTH(RQ)" +
                " ) AS grouped ON t.RQ = grouped.MaxRQ" +
                " WHERE t.BKGS = ?" +
                " ORDER BY t.QYGS, t.SHIQU, t.RQ";

//        String sql ="SELECT t.RQ AS RQ,t.QYGS AS QYGS,t.XSZZ AS XSZZ,t.SHENGQU AS SHENGQU,t.SHIQU AS SHIQU,t.QX AS QX,t.QCYE AS QCYE," +
//                "    t.LJXS AS LJXS,t.LJHK AS LJHK,t.YSYE AS YSYE,t_last_year.YSYE AS LAST_YEAR_YSYE,t.ZLFX0_60 AS ZLFX0_60," +
//                "    t.ZLFX60_1 AS ZLFX60_1,t.ZLFX1_2 AS ZLFX1_2,t.ZLFX2_3 AS ZLFX2_3,t.ZLFX3_4 AS ZLFX3_4,t.ZLFX4_5 AS ZLFX4_5,t.ZLFX5 AS ZLFX5 " +
//                " FROM BO_EU_BNBM_DATALINKUP_XS_YSL t " +
//                " INNER JOIN ( " +
//                "    SELECT QYGS,SHIQU,MAX(RQ) AS MaxRQ,YEAR(RQ) AS Year,MONTH(RQ) AS Month" +
//                "    FROM BO_EU_BNBM_DATALINKUP_XS_YSL " +
//                "    WHERE DATE(RQ) >= ? AND BKGS = ? " +
//                "    GROUP BY QYGS, SHIQU, YEAR(RQ), MONTH(RQ)" +
//                " ) AS grouped ON t.QYGS = grouped.QYGS AND t.SHIQU = grouped.SHIQU AND t.RQ = grouped.MaxRQ" +
//                " LEFT JOIN (" +
//                "    SELECT QYGS,SHIQU,YSYE,YEAR(RQ) AS Year,MONTH(RQ) AS Month,MAX(RQ) AS MaxRQ " +
//                "    FROM BO_EU_BNBM_DATALINKUP_XS_YSL " +
//                "    WHERE BKGS = ? GROUP BY QYGS, SHIQU, YEAR(RQ), MONTH(RQ)" +
//                " ) t_last_year " +
//                "    ON t.QYGS = t_last_year.QYGS" +
//                "    AND t.SHIQU = t_last_year.SHIQU " +
//                "    AND t_last_year.Year = grouped.Year - 1" +
//                "    AND t_last_year.Month = grouped.Month" +
//                " WHERE t.BKGS = ?  " +
//                " ORDER BY t.QYGS, t.SHIQU, t.RQ";

        List<RowMap> maps = DBSql.getMaps(sql, DATE_FORMAT.format(dateRange.getStartDate()), bkgs, bkgs);
        // 获取公司位置信息
        List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
        Map<String, Location> resultMap = companyList.stream()
                .filter(row -> row.get("GSMC") != null)
                .collect(Collectors.toMap(
                        row -> row.get("GSMC").toString(),
                        row -> new Location(
                                row.get("JD") != null ? row.get("JD").toString() : null,
                                row.get("WD") != null ? row.get("WD").toString() : null
                        ),
                        (existing, replacement) -> existing
                ));

        if (maps==null){
            LOGGER.info("应收账款数据第无数据");
            return;
        }
        // 分页查询应收账款数据
        int page = 0;
        boolean hasMore = true;
        ArrayList<BO> bos = new ArrayList<>();
        for (RowMap map : maps) {
            String xszz = map.getString("XSZZ");
            String rq = map.getString("RQ");
            String qygs = map.getString("QYGS");
            BO bo = new BO();
            bo.set("YEARMONTH", rq.substring(0, 7));
            bo.set("BKGS", bkgs);
            bo.set("QYGS", qygs);
            bo.set("GC", xszz);
            bo.set("SQ", map.getString("SHENGQU"));
            bo.set("CITY", map.getString("SHIQU"));
            bo.set("QX", map.getString("QX"));
            if (resultMap.containsKey(xszz)) {
                Location location = resultMap.get(xszz);
                bo.set("JD", location.getLongitude());
                bo.set("WD", location.getLatitude());
            }
            bo.set("QCYE", map.getDouble("QCYE"));
            bo.set("NFH", map.getDouble("LJXS"));
            bo.set("NHK", map.getDouble("LJHK"));
            bo.set("YSZE", map.getDouble("YSYE"));
            bo.set("ZL60", map.getDouble("ZLFX0_60"));
            bo.set("ZL60_1", map.getDouble("ZLFX60_1"));
            bo.set("ZL1_2", map.getDouble("ZLFX1_2"));
            bo.set("ZL2_3", map.getDouble("ZLFX2_3"));
            bo.set("ZL3_4", map.getDouble("ZLFX3_4"));
            bo.set("ZL4_5", map.getDouble("ZLFX4_5"));
            bo.set("ZL5", map.getDouble("ZLFX5"));
//            bo.set("QYTQYSZK", map.getString("LAST_YEAR_YSYE"));
            if (gsjcMap.containsKey(xszz)) {
                bo.set("GCJC", gsjcMap.get(xszz));
            }
            bos.add(bo);
        }

        // 批量新增BO
        if (!bos.isEmpty()) {
            for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
                int end = Math.min(bos.size(), i + BATCH_SIZE);
                List<BO> batchList = bos.subList(i, end);
                SDK.getBOAPI().createDataBO(BO_EU_XS_YSZK, batchList, UserContext.fromUID("admin"));
            }
            totalCount += bos.size();
            LOGGER.info("应收账款数据第{}页处理完成，本页{}条记录，累计{}条", page + 1, bos.size(), totalCount);
            page++;
        }


        LOGGER.info("应收账款数据处理完成，共处理{}条记录", totalCount);
    }

    /**
     * 区域两金占比
     * @param dateRange 时间范围
     * @param bkgs 时间范围
     */
    private void newProcessRegionTwoFundsRatio(DateRange dateRange, String bkgs) {
        LOGGER.info("开始处理区域两金占比，年月: {}-{}, 板块公司: {}", dateRange.getStartDate(),dateRange.getEndDate(), bkgs);

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_QYLJZB + " WHERE YEARMONTH >= ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(deleteSql, new Object[]{YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs});
            LOGGER.info("区域两金占比数据-已删除{}-{}条营业收入记录", YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), deleted);
        }catch (Exception e){
            LOGGER.error("区域两金占比-删除数据{}年月-{}板块数据错误，删除sql为：{}，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,deleteSql,e.getMessage());
            throw e;
        }

        try {
            // 第一个SQL：查询应收账款数据
            String receivableSql = "SELECT t1.RQ AS RQ, t1.XSZZ AS XSZZ, t1.QYGS AS QYGS, t1.BKGS AS BKGS," +
                    " DATE_FORMAT( t1.RQ, '%Y-%m' ) ASyear_month, t1.RQ AS max_rq, (SUM( t1.YSYE )/10000) AS YSZK," +
                    " SUM(t1.LJHK) AS LJHK,SUM(t1.LJXS) AS LJXS," +
                    " CASE " +
                    "        WHEN SUM(t1.LJXS) != 0 THEN SUM(t1.LJHK) / SUM(t1.LJXS)" +
                    "        ELSE NULL " +
                    "    END AS hkl" +
                    " FROM BO_EU_BNBM_DATALINKUP_XS_YSL t1" +
                    " INNER JOIN (" +
                    " SELECT QYGS, BKGS, DATE_FORMAT( RQ, '%Y-%m' ) ASyear_month, MAX( RQ ) AS max_rq" +
                    " FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
                    " WHERE RQ >= ? AND RQ < ? AND BKGS = ?" +
                    " GROUP BY QYGS,BKGS,DATE_FORMAT ( RQ, '%Y-%m' )" +
                    " ) t2 ON t1.QYGS = t2.QYGS AND t1.BKGS = t2.BKGS AND t1.RQ = t2.max_rq" +
                    " WHERE t1.RQ >= ? AND t1.RQ < ? AND t1.BKGS = ?" +
                    " GROUP BY t1.QYGS,t1.BKGS,DATE_FORMAT ( t1.RQ, '%Y-%m' ),t1.RQ";

//            String receivableSql = "SELECT t1.RQ AS RQ,t1.XSZZ AS XSZZ,t1.QYGS AS QYGS,t1.BKGS AS BKGS,DATE_FORMAT(t1.RQ, '%Y-%m') ASyear_month," +
//                    "    t1.RQ AS max_rq,(SUM(t1.YSYE)/1000) AS YSZK,SUM(t1.LJHK) AS LJHK,SUM(t1.LJXS) AS LJXS," +
//                    "    CASE " +
//                    "        WHEN SUM(t1.LJXS) != 0 THEN SUM(t1.LJHK) / SUM(t1.LJXS)" +
//                    "        ELSE NULL " +
//                    "    END AS hkl," +
//                    "    (SELECT SUM(t3.YSYE)/1000 " +
//                    "     FROM BO_EU_BNBM_DATALINKUP_XS_YSL t3" +
//                    "     INNER JOIN (" +
//                    "         SELECT QYGS, BKGS, DATE_FORMAT(RQ, '%Y-%m') ASyear_month, MAX(RQ) AS max_rq" +
//                    "         FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
//                    "         WHERE RQ >= DATE_SUB(?, INTERVAL 1 YEAR) " +
//                    "           AND RQ < DATE_SUB(?, INTERVAL 1 YEAR)" +
//                    "           AND BKGS = ?" +
//                    "         GROUP BY QYGS, BKGS, DATE_FORMAT(RQ, '%Y-%m')" +
//                    "     ) t4 ON t3.QYGS = t4.QYGS AND t3.BKGS = t4.BKGS AND t3.RQ = t4.max_rq" +
//                    "     WHERE t3.RQ >= DATE_SUB(?, INTERVAL 1 YEAR)" +
//                    "       AND t3.RQ < DATE_SUB(?, INTERVAL 1 YEAR)" +
//                    "       AND t3.BKGS = ? " +
//                    "       AND DATE_FORMAT(t3.RQ, '%Y-%m') = DATE_FORMAT(DATE_SUB(t1.RQ, INTERVAL 1 YEAR), '%Y-%m')" +
//                    "     GROUP BY t3.QYGS, t3.BKGS, DATE_FORMAT(t3.RQ, '%Y-%m')" +
//                    "    ) AS last_year_YSZK" +
//                    " FROM BO_EU_BNBM_DATALINKUP_XS_YSL t1 " +
//                    " INNER JOIN (" +
//                    "    SELECT QYGS, BKGS, DATE_FORMAT(RQ, '%Y-%m') ASyear_month, MAX(RQ) AS max_rq" +
//                    "    FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
//                    "    WHERE RQ >= ? AND RQ < ? AND BKGS = ?" +
//                    "    GROUP BY QYGS, BKGS, DATE_FORMAT(RQ, '%Y-%m')" +
//                    " ) t2 ON t1.QYGS = t2.QYGS AND t1.BKGS = t2.BKGS AND t1.RQ = t2.max_rq" +
//                    " WHERE t1.RQ >= ? AND t1.RQ < ? AND t1.BKGS = ? " +
//                    " GROUP BY t1.QYGS, t1.BKGS, DATE_FORMAT(t1.RQ, '%Y-%m'), t1.RQ";

            String startDate = DATE_FORMAT.format(dateRange.getStartDate());
            String endDate = DATE_FORMAT.format(dateRange.getEndDate());

            LOGGER.info("应收账款数据查SQL: {}", receivableSql);
            List<RowMap> receivableMaps = DBSql.getMaps(receivableSql, startDate, endDate,
                    bkgs,startDate, endDate, bkgs);

            if (receivableMaps.isEmpty()) {
                LOGGER.info("{}应收账款数据无数据，停止分页查询", bkgs);
            } else {
                ArrayList<BO> bos = new ArrayList<>();

                // 收集所有销售组织用于库存查询
                List<String> xszzList = new ArrayList<>();
                Map<String, RowMap> receivableMap = new HashMap<>();

                for (RowMap map : receivableMaps) {
                    String qygs = map.getString("QYGS");
                    List<RowMap> maps = DBSql.getMaps("SELECT * FROM BO_EU_BNBM_QYGSDYB WHERE QYGS = '" + qygs + "'");
                    for (RowMap rowMap : maps) {
                        String xszz = rowMap.getString("XSZZ");
                        xszzList.add(xszz);
                        receivableMap.put(xszz, map);
                    }
                }
                //先查询区域公司授信额度维护表
                List<BO> sxedList = SDK.getBOAPI().query("BO_EU_DATALINKUP_QYGSED").orderBy("QYGS").desc().list();
                // 合并数据并创建BO对象
                for (RowMap receivable : receivableMaps) {
                    String xszz = receivable.getString("XSZZ");
                    double yszk = receivable.getDouble("YSZK");
                    String year_month = receivable.getString("ASyear_month");
                    BO bo = new BO();
                    String qygs = receivable.getString("QYGS");
                    String rq = receivable.getString("RQ");
                    bo.set("YEARMONTH", year_month);
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", qygs);
                    bo.set("YSZK", yszk);
//                    bo.set("CCJE", kcje);
                    bo.set("LJHK", receivable.getString("LJHK"));
                    bo.set("LJXS", receivable.getString("LJXS"));
                    bo.set("HKL", receivable.getString("HKL"));
                    //增加额度使用率情况
                    bo.set("EDSYL", SaleUtil.calculateResult(sxedList,bkgs,receivable.getString("QYGS"),yszk));
//                       bo.set("QYTQYSZK", receivable.getString("last_year_YSZK"));
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    int[] admins = SDK.getBOAPI().createDataBO(BO_EU_XS_QYLJZB, bos, UserContext.fromUID("admin"));
                    LOGGER.info("{}：{}-{}范围区域两金占比数据处理完成，查询{}条记录，累计{}条",
                            bkgs, dateRange.getStartDate(), dateRange.getEndDate(), bos.size(), admins[0]);
                }
            }
        }catch (Exception e){
            LOGGER.error("两金占比-新增数据{}年月-{}板块数据错误，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,e.getMessage());
            throw e;
        }

    }

    /**
     * 处理销量销额数据
     * @param dateRange 时间范围
     * @param bkgs 板块公司
     */
    private void newProcessSalesVolumeData(DateRange dateRange, String bkgs) {
        LOGGER.info("开始处理销量销额数据，年月: {}-{}, 板块公司: {}", dateRange.getStartDate(),dateRange.getEndDate(), bkgs);

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_XLXE + " WHERE YEARMONTH >= ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(deleteSql, new Object[]{YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs});
            LOGGER.info("销量销额数据-已删除{}-{}条营业收入记录", YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), deleted);
        }catch (Exception e){
            LOGGER.error("销量销额-删除数据{}年月-{}板块数据错误，删除sql为：{}，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,deleteSql,e.getMessage());
            throw e;
        }

        try {
            // 获取公司位置信息
            List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
            Map<String, Location> resultMap = companyList.stream()
                    .filter(row -> row.get("GSMC") != null)
                    .collect(Collectors.toMap(
                            row -> row.get("GSMC").toString(),
                            row -> new Location(
                                    row.get("JD") != null ? row.get("JD").toString() : null,
                                    row.get("WD") != null ? row.get("WD").toString() : null
                            ),
                            (existing, replacement) -> existing
                    ));
            // 获取公司简称
            List<RowMap> gsjcList = DBSql.getMaps("SELECT GSMC,JC FROM BO_EU_BNBM_ZZWHB");
            Map<String, String> gsjcMap = gsjcList.stream()
                    .filter(row -> {
                        String gsmc = row.getString("GSMC");
                        String jc = row.getString("JC");
                        return gsmc != null && jc != null;
                    })
                    .collect(Collectors.toMap(
                            row -> row.getString("GSMC"),
                            row -> row.getString("JC"),
                            (existing, replacement) -> existing // 处理重复key
                    ));

            String querySql = "SELECT DZRQ,QYGS, KCZZ, " +
                    " CASE " +
                    "        WHEN BKGS = '龙牌' AND LB_1 IN ('装饰石膏板', '鲁班装饰万能板', '石膏板') THEN '石膏板'" +
                    "        WHEN BKGS = '泰山石膏' AND LB_1 IN ('装饰板', '石膏板') THEN '石膏板'" +
                    "        ELSE LB_1" +
                    "    END AS LB_1," +
                    " LB_2, LB_3, SQ, CS, QY, SUM(ZSSL) AS XL," +
                    " SUM(SSJERMB) AS XE, SUM(XSSL) AS TSXL, SUM(NMNY) AS BHSXE,YEARMONTH" +
                    " FROM " + SALES_DETAIL_TABLE +
                    " WHERE DZRQ >= DATE_FORMAT(?, '%Y-%m-01') AND BKGS = ?" +
                    " GROUP BY QYGS, KCZZ, " +
                    " CASE " +
                    "        WHEN BKGS = '龙牌' AND LB_1 IN ('装饰石膏板', '鲁班装饰万能板', '石膏板') THEN '石膏板'" +
                    "        WHEN BKGS = '泰山石膏' AND LB_1 IN ('装饰板', '石膏板') THEN '石膏板'" +
                    "        ELSE LB_1" +
                    "    END," +
                    " LB_2, LB_3, SQ, CS, QY, YEARMONTH";

//            String querySql = "SELECT t1.DZRQ, t1.QYGS, t1.KCZZ, t1.LB_1, t1.LB_2, t1.LB_3, t1.SQ, t1.CS, t1.QY," +
//                    " SUM(t1.ZSSL) AS XL, SUM(t1.SSJERMB) AS XE, SUM(t1.XSSL) AS TSXL, SUM(t1.NMNY) AS BHSXE," +
//                    " t1.YEARMONTH, COALESCE(SUM(t2.ZSSL), 0) AS sntqXL, COALESCE(SUM(t2.SSJERMB), 0) AS sntqxe," +
//                    " COALESCE(SUM(t2.XSSL), 0) AS sntqtsxl " +
//                    " FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ t1" +
//                    " LEFT JOIN BO_EU_BNBM_DATALINKUP_XS_XSL_HZ t2 ON t1.QYGS = t2.QYGS AND t1.KCZZ = t2.KCZZ" +
//                    " AND t1.LB_1 = t2.LB_1 AND t1.LB_2 = t2.LB_2 AND t1.LB_3 = t2.LB_3 AND t1.SQ = t2.SQ" +
//                    " AND t1.CS = t2.CS AND t1.QY = t2.QY AND YEAR(t2.DZRQ) = YEAR(t1.DZRQ) - 1" +
//                    " AND MONTH(t2.DZRQ) = MONTH(t1.DZRQ) AND t2.BKGS = ?" +
//                    " WHERE t1.DZRQ >= ? AND t1.DZRQ < ? AND t1.BKGS = ?" +
//                    " GROUP BY t1.DZRQ, t1.QYGS, t1.KCZZ, t1.LB_1, t1.LB_2, t1.LB_3, t1.SQ, t1.CS, t1.QY," +
//                    " t1.YEARMONTH ORDER BY t1.DZRQ, t1.QYGS, t1.KCZZ";

            LOGGER.info("销量销额数据查询，SQL: {}", querySql);
            List<RowMap> maps = DBSql.getMaps(querySql, DATE_FORMAT.format(dateRange.getStartDate()), bkgs);

            if (maps.isEmpty()) {
                LOGGER.info("销量销额数据无数据，停止查询");
            } else {
                ArrayList<BO> bos = new ArrayList<>();
                // 循环外先获取下公装家装、基材面材类别
                List<BO> gzjzList = SDK.getBOAPI().query("BO_EU_DATALINKUP_CPJZGZJCMC").desc().list();
                for (RowMap map : maps) {
                    String dzrq = map.getString("DZRQ");
                    String gc = map.getString("KCZZ");
                    String yearmonth = map.getString("YEARMONTH");
                    String qygs = map.getString("QYGS");
                    String lb_1 = map.getString("LB_1");
                    BO bo = new BO();
                    bo.set("YEARMONTH", yearmonth.substring(0, 4) + "-" + yearmonth.substring(4));
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", qygs);
                    bo.set("GC", gc);
                    bo.set("LB_1",lb_1 );
                    bo.set("LB_2", map.getString("LB_2"));
                    bo.set("LB_3", map.getString("LB_3"));
                    bo.set("SQ", map.getString("SQ"));
                    bo.set("CITY", map.getString("CS"));
                    bo.set("QX", map.getString("QY"));
                    if (resultMap.containsKey(gc)) {
                        Location location = resultMap.get(gc);
                        bo.set("JD", location.getLongitude());
                        bo.set("WD", location.getLatitude());
                    }
                    if ("石膏板".equals(lb_1)){
                        bo.set("XL", map.getDouble("TSXL"));
                        bo.set("SNTQXL", map.getString("sntqtsxl"));
                    } else if ((bkgs.equals("北新防水") && ("高分子".equals(lb_1) || "卷材".equals(lb_1) || "涂料".equals(lb_1)))
                            || (bkgs.equals("北新涂料") && "涂料".equals(lb_1))) {
                        bo.set("XL", map.getDouble("TSXL"));
                        bo.set("SNTQXL", map.getString("sntqtsxl"));
                    } else {
                        bo.set("XL", map.getDouble("XL"));
                        bo.set("SNTQXL", map.getString("sntqXL"));
                    }
                    Double ssjermb = map.getDouble("XE");
                    Double xe = map.getDouble("BHSXE");
                    bo.set("XE", xe);
                    // 匹配公装家装类别，如果未匹配到，则默认未其他
                    String[] gzjzStrings = SaleUtil.matchSingleField(bkgs, map.getString("LB_1"), map.getString("LB_2"),map.getString("LB_3"), gzjzList, "其他", "其他","其他");
                    bo.set("MC_JC", gzjzStrings[1]);//面材/基材
                    bo.set("JZ_GZ", gzjzStrings[0]);//家装/工装
                    bo.set("PROD_CAT", gzjzStrings[2]);//产品类型
                    bo.set("PBGNB", gzjzStrings[3]);//普板/功能板
                    bo.set("ISOEM", gzjzStrings[4]);//是否OEM板
//                    bo.set("SNTQXE", map.getString("sntqxe"));
                    bo.set("BHSYYSR", ssjermb);
                    if (gsjcMap.containsKey(gc)) {
                        bo.set("GCJC", gsjcMap.get(gc));
                    }
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    int[] admins = SDK.getBOAPI().createDataBO(BO_EU_XS_XLXE, bos, UserContext.fromUID("admin"));
                    LOGGER.info("{}-销量销额数据处理完成，共查询除{}条记录，导入{}条", bkgs, bos.size(), admins[0]);
                }
            }
        }catch (Exception e){
            LOGGER.error("销量销额-新增数据{}年月-{}板块数据错误，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,e.getMessage());
            throw e;
        }
    }

    /**
     * 处理营业收入数据
     * @param dateRange 时间范围
     * @param bkgs 板块公司
     */
    private void newProcessRevenueData(DateRange dateRange, String bkgs) {
        LOGGER.info("开始处理营业收入数据，年月: {}-{}, 板块公司: {}", dateRange.getStartDate(),dateRange.getEndDate(), bkgs);

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_YESR + " WHERE YEARMONTH >= ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(deleteSql, new Object[]{YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs});
            LOGGER.info("营业收入数据-已删除{}-{}条营业收入记录", YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), deleted);
        }catch (Exception e){
            LOGGER.error("营业收入-删除数据{}年月-{}板块数据错误，删除sql为：{}，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,deleteSql,e.getMessage());
            throw e;
        }

        try {
            // 获取公司位置信息
            List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
            Map<String, Location> resultMap = companyList.stream()
                    .filter(row -> row.get("GSMC") != null)
                    .collect(Collectors.toMap(
                            row -> row.get("GSMC").toString(),
                            row -> new Location(
                                    row.get("JD") != null ? row.get("JD").toString() : null,
                                    row.get("WD") != null ? row.get("WD").toString() : null
                            ),
                            (existing, replacement) -> existing
                    ));

            String querySql = "SELECT DZRQ, QYGS, KCZZ, " +
                    " CASE " +
                    "        WHEN BKGS = '龙牌' AND LB_1 IN ('装饰石膏板', '鲁班装饰万能板', '石膏板') THEN '石膏板'" +
                    "        WHEN BKGS = '泰山石膏' AND LB_1 IN ('装饰板', '石膏板') THEN '石膏板'" +
                    "        ELSE LB_1" +
                    "    END AS LB_1," +
                    " LB_2, LB_3, SQ, CS, QY, SUM(NMNY) as BHSYYSR, SUM(SSJERMB) AS YYSR, YEARMONTH" +
                    " FROM " + SALES_DETAIL_TABLE +
                    " WHERE DZRQ >= DATE_FORMAT(?, '%Y-%m-01') AND DZRQ < ? AND BKGS = ?" +
                    " GROUP BY QYGS, KCZZ, " +
                    " CASE " +
                    "        WHEN BKGS = '龙牌' AND LB_1 IN ('装饰石膏板', '鲁班装饰万能板', '石膏板') THEN '石膏板'" +
                    "        WHEN BKGS = '泰山石膏' AND LB_1 IN ('装饰板', '石膏板') THEN '石膏板'" +
                    "        ELSE LB_1" +
                    "    END ," +
                    " LB_2, LB_3, SQ, CS, QY, YEARMONTH";

//            String querySql = "SELECT curr.DZRQ,curr.QYGS,curr.KCZZ,curr.LB_1,curr.LB_2,curr.LB_3,curr.SQ,curr.CS,curr.QY," +
//                    "       curr.YEARMONTH,curr.BHSYYSR,curr.YYSR,COALESCE(prev.BHSYYSR, 0) AS QNTQBHSYYSR,COALESCE(prev.YYSR, 0) AS QNTQYYSR" +
//                    " FROM (" +
//                    "         SELECT DZRQ,QYGS,KCZZ,LB_1,LB_2,LB_3,SQ," +
//                    "             CS,QY,YEARMONTH,SUM(NMNY) AS BHSYYSR,SUM(SSJERMB) AS YYSR" +
//                    "         FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ" +
//                    "         WHERE DZRQ >= ? AND DZRQ < ? AND BKGS = ?" +
//                    "         GROUP BY QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY, YEARMONTH" +
//                    "     ) curr" +
//                    "         LEFT JOIN (" +
//                    "    SELECT QYGS,KCZZ,LB_1,LB_2,LB_3,SQ,CS," +
//                    "        QY,YEARMONTH,SUM(NMNY) AS BHSYYSR,SUM(SSJERMB) AS YYSR" +
//                    "    FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ" +
//                    "    WHERE DZRQ >= DATE_SUB(?, INTERVAL 1 YEAR)AND DZRQ < DATE_SUB(?, INTERVAL 1 YEAR)AND BKGS = ?" +
//                    "    GROUP BY QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY, YEARMONTH" +
//                    " ) prev" +
//                    "   ON curr.QYGS = prev.QYGS AND curr.KCZZ = prev.KCZZ AND curr.LB_1 = prev.LB_1 AND curr.LB_2 = prev.LB_2" +
//                    "       AND curr.LB_3 = prev.LB_3 AND curr.SQ = prev.SQ AND curr.CS = prev.CS AND curr.QY = prev.QY" +
//                    "       AND curr.YEARMONTH = DATE_FORMAT(prev.YEARMONTH + INTERVAL 1 YEAR, '%Y%m')";

            LOGGER.info("营业收入数据查询，SQL: {}", querySql);
            List<RowMap> maps = DBSql.getMaps(querySql, DATE_FORMAT.format(dateRange.getStartDate()),
                    DATE_FORMAT.format(dateRange.getEndDate()), bkgs);

            if (maps.isEmpty()) {
                LOGGER.info("营业收入数据无数据，停止查询");
            } else {
                ArrayList<BO> bos = new ArrayList<>();
                for (RowMap map : maps) {
                    String gc = map.getString("KCZZ");
                    String yearmonth = map.getString("YEARMONTH");
                    String dzrq = map.getString("DZRQ");
                    String qygs = map.getString("QYGS");
                    String sq = map.getString("SQ");
                    BO bo = new BO();
                    bo.set("YEARMONTH", yearmonth.substring(0, 4) + "-" + yearmonth.substring(4));
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", map.getString("QYGS"));
                    bo.set("GC", gc);
                    bo.set("LB_1", map.getString("LB_1"));
                    bo.set("LB_2", map.getString("LB_2"));
                    bo.set("LB_3", map.getString("LB_3"));
                    bo.set("SQ", sq);
                    bo.set("CITY", map.getString("CS"));
                    bo.set("QX", map.getString("QY"));
                    if (resultMap.containsKey(gc)) {
                        Location location = resultMap.get(gc);
                        bo.set("JD", location.getLongitude());
                        bo.set("WD", location.getLatitude());
                    }
                    bo.set("YYSR", map.getDouble("YYSR"));
                    bo.set("BHSYYSR", map.getDouble("BHSYYSR"));
//                    bo.set("QNTQYYSR", map.getDouble("QNTQYYSR"));
//                    bo.set("QNTQBHSYYSR", map.getDouble("QNTQBHSYYSR"));
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    int[] admins = SDK.getBOAPI().createDataBO(BO_EU_XS_YESR, bos, UserContext.fromUID("admin"));
                    LOGGER.info("{}-营业收入数据处理完成，共查询{}条记录，导入{}条", bkgs, bos.size(), admins[0]);
                }
            }
        }catch (Exception e){
            LOGGER.error("营业收入-新增数据{}年月-{}板块数据错误，请检查数据库链接：{}",
                    YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,e.getMessage());
            throw e;
        }
    }

    /**
     * 按当前日期计算（无时间范围时使用）
     */
    private void calculateForCurrentDate(String bkgs) {
        Calendar cal = Calendar.getInstance();
        DateRange dateRange = new DateRange();

        // 设置为当前月的第一天
        cal.set(Calendar.DAY_OF_MONTH, 1);
        dateRange.setStartDate(cal.getTime());

        // 设置为当前月的最后一天
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        dateRange.setEndDate(cal.getTime());



    }

    /**
     * 计算月度维度数据
     */
    private void calculateMonthlyData(DateRange dateRange, String bkgs) {
        Connection conn = null;
        try {
            conn = DBSql.open();
//            conn.setAutoCommit(false);
            // 获取时间范围内的所有月份
            List<String> yearMonths = getYearMonthsBetweenDates(dateRange.getStartDate(), dateRange.getEndDate());

            for (String yearMonth : yearMonths) {
                LOGGER.info("开始处理{}月份的数据，板块公司: {}", yearMonth, bkgs);
                // 3. 处理应收账款数据
                LOGGER.info("开始应收账款数据");
                processReceivableData(conn, yearMonth, bkgs);
            }
//            conn.commit();
            LOGGER.info("所有月份数据处理完成");
        }catch (Exception e) {
            try {
                if (conn != null) conn.rollback();
            } catch (Exception rollbackEx) {
                LOGGER.error("回滚事务失败", rollbackEx);
            }
            String errorMsg = "月度数据处理失败: " + e.getMessage();
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        } finally {
            DBSql.close(conn);
        }
    }

    /**
     * 处理营业收入数据
     */
    private void processRevenueData(Connection conn, String yearMonth, String bkgs) throws Exception {
        LOGGER.info("开始处理营业收入数据，年月: {}, 板块公司: {}", yearMonth, bkgs);
        int totalCount = 0;

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_YESR + " WHERE YEARMONTH = ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(conn, deleteSql, new Object[]{yearMonth, bkgs});
            LOGGER.info("营业收入数据-已删除{}条营业收入记录", deleted);
        }catch (Exception e){
            LOGGER.error("营业收入-删除数据{}数据错误，删除sql为：{}，请检查数据库链接：{}",bkgs,deleteSql,e.getMessage());
            throw e;
        }

        // 获取公司位置信息
        List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
        Map<String, Location> resultMap = companyList.stream()
                .filter(row -> row.get("GSMC") != null)
                .collect(Collectors.toMap(
                        row -> row.get("GSMC").toString(),
                        row -> new Location(
                                row.get("JD") != null ? row.get("JD").toString() : null,
                                row.get("WD") != null ? row.get("WD").toString() : null
                        ),
                        (existing, replacement) -> existing
                ));

        // 分页查询营业收入数据
        int page = 0;
        boolean hasMore = true;
        while (hasMore) {
            int offset = page * PAGE_SIZE;
            String querySql = "SELECT QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY, " +
                    "SUM(SSJERMB) as YYSR " +
                    "FROM " + SALES_DETAIL_TABLE + " " +
                    "WHERE YEARMONTH = ? AND BKGS = ? " +
                    "GROUP BY QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY " +
                    "LIMIT " + PAGE_SIZE + " OFFSET " + offset;

            LOGGER.info("营业收入数据查询第{}页，SQL: {}", page + 1, querySql);
            List<RowMap> maps = DBSql.getMaps(conn, querySql, yearMonth.replace("-", ""), bkgs);

            if (maps.isEmpty()) {
                hasMore = false;
                LOGGER.info("营业收入数据第{}页无数据，停止分页查询", page + 1);
            } else {
                ArrayList<BO> bos = new ArrayList<>();
                for (RowMap map : maps) {
                    String gc = map.getString("KCZZ");
                    BO bo = new BO();
                    bo.set("YEARMONTH", yearMonth);
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", map.getString("QYGS"));
                    bo.set("GC", gc);
                    bo.set("LB_1", map.getString("LB_1"));
                    bo.set("LB_2", map.getString("LB_2"));
                    bo.set("LB_3", map.getString("LB_3"));
                    bo.set("SQ", map.getString("SQ"));
                    bo.set("CITY", map.getString("CS"));
                    bo.set("QX", map.getString("QY"));
                    if (resultMap.containsKey(gc)) {
                        Location location = resultMap.get(gc);
                        bo.set("JD", location.getLongitude());
                        bo.set("WD", location.getLatitude());
                    }
                    bo.set("YYSR", map.getDouble("YYSR"));
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
                        int end = Math.min(bos.size(), i + BATCH_SIZE);
                        List<BO> batchList = bos.subList(i, end);
                        SDK.getBOAPI().createDataBO(BO_EU_XS_YESR, batchList, UserContext.fromUID("admin"));
                    }
                    totalCount += bos.size();
                    LOGGER.info("营业收入数据第{}页处理完成，本页{}条记录，累计{}条", page + 1, bos.size(), totalCount);
                }
                page++;
            }
        }
        LOGGER.info("营业收入数据处理完成，共处理{}条记录", totalCount);
    }

    /**
     * 处理销量销额数据（分页查询）
     */
    private void processSalesVolumeData(Connection conn, String yearMonth, String bkgs) throws Exception {
        LOGGER.info("开始处理销量销额数据，年月: {}, 板块公司: {}", yearMonth, bkgs);
        int totalCount = 0;

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_XLXE + " WHERE YEARMONTH = ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(conn, deleteSql, new Object[]{yearMonth, bkgs});
            LOGGER.info("销量销额-已删除{}条记录", deleted);
        } catch (Exception e) {
            LOGGER.error("销量销额-删除{}数据错误，删除sql为：{}，请检查数据库链接：{}", bkgs, deleteSql, e.getMessage());
            throw e;
        }

        // 获取公司位置信息
        List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
        Map<String, Location> resultMap = companyList.stream()
                .filter(row -> row.get("GSMC") != null)
                .collect(Collectors.toMap(
                        row -> row.get("GSMC").toString(),
                        row -> new Location(
                                row.get("JD") != null ? row.get("JD").toString() : null,
                                row.get("WD") != null ? row.get("WD").toString() : null
                        ),
                        (existing, replacement) -> existing
                ));

        // 分页查询销量销额数据
        int page = 0;
        boolean hasMore = true;
        while (hasMore) {
            int offset = page * PAGE_SIZE;
            String querySql = "SELECT QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY, " +
                    "SUM(ZSSL) as XL, SUM(SSJERMB) as XE ,SUM(XSSL) AS TSXL " +
                    "FROM " + SALES_DETAIL_TABLE + " " +
                    "WHERE YEARMONTH = ? AND BKGS = ? " +
                    "GROUP BY QYGS, KCZZ, LB_1, LB_2, LB_3, SQ, CS, QY " +
                    "LIMIT " + PAGE_SIZE + " OFFSET " + offset;

            LOGGER.info("销量销额数据查询第{}页，SQL: {}", page + 1, querySql);
            List<RowMap> maps = DBSql.getMaps(conn, querySql, yearMonth.replace("-", ""), bkgs);

            if (maps.isEmpty()) {
                hasMore = false;
                LOGGER.info("销量销额数据第{}页无数据，停止分页查询", page + 1);
            } else {
                ArrayList<BO> bos = new ArrayList<>();
                for (RowMap map : maps) {
                    String gc = map.getString("KCZZ");
                    BO bo = new BO();
                    bo.set("YEARMONTH", yearMonth);
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", map.getString("QYGS"));
                    bo.set("GC", gc);
                    bo.set("LB_1", map.getString("LB_1"));
                    bo.set("LB_2", map.getString("LB_2"));
                    bo.set("LB_3", map.getString("LB_3"));
                    bo.set("SQ", map.getString("SQ"));
                    bo.set("CITY", map.getString("CS"));
                    bo.set("QX", map.getString("QY"));
                    if (resultMap.containsKey(gc)) {
                        Location location = resultMap.get(gc);
                        bo.set("JD", location.getLongitude());
                        bo.set("WD", location.getLatitude());
                    }
                    if ("石膏板".equals(map.getString("LB_1"))){
                        bo.set("XL", map.getDouble("TSXL"));
                    }else {
                        bo.set("XL", map.getDouble("XL"));
                    }
                    bo.set("XE", map.getDouble("XE"));
                    bo.set("MC_JC", Math.random()%2==0?"面材":"基材");
                    bo.set("JZ_GZ", Math.random()%2==0?"家装":"工装");
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
                        int end = Math.min(bos.size(), i + BATCH_SIZE);
                        List<BO> batchList = bos.subList(i, end);
                        SDK.getBOAPI().createDataBO(BO_EU_XS_XLXE, batchList, UserContext.fromUID("admin"));
                    }
                    totalCount += bos.size();
                    LOGGER.info("销量销额数据第{}页处理完成，本页{}条记录，累计{}条", page + 1, bos.size(), totalCount);
                }
                page++;
            }
        }
        LOGGER.info("销量销额数据处理完成，共处理{}条记录", totalCount);
    }

    /**
     * 处理应收账款数据（分页查询）
     */
    private void processReceivableData(Connection conn, String yearMonth, String bkgs) throws Exception {
        LOGGER.info("开始处理应收账款数据，年月: {}, 板块公司: {}", yearMonth, bkgs);
        int totalCount = 0;

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_YSZK + " WHERE YEARMONTH = ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(conn, deleteSql, new Object[]{yearMonth, bkgs});
            LOGGER.info("应收账款-已删除{}条记录", deleted);
        } catch (Exception e) {
            LOGGER.error("应收账款-删除{}数据错误，删除sql为：{}，请检查数据库链接：{}", bkgs, deleteSql, e.getMessage());
            throw e;
        }

        // 获取指定年月最后一天
        Calendar cal = Calendar.getInstance();
        cal.setTime(YEAR_MONTH_FORMAT.parse(yearMonth));
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        String lastDayOfMonth = DATE_FORMAT.format(cal.getTime());

        // 获取公司位置信息
        List<RowMap> companyList = DBSql.getMaps("SELECT GSMC,JD,WD FROM BO_EU_BNBM_DATALINKUP_GSJWD");
        Map<String, Location> resultMap = companyList.stream()
                .filter(row -> row.get("GSMC") != null)
                .collect(Collectors.toMap(
                        row -> row.get("GSMC").toString(),
                        row -> new Location(
                                row.get("JD") != null ? row.get("JD").toString() : null,
                                row.get("WD") != null ? row.get("WD").toString() : null
                        ),
                        (existing, replacement) -> existing
                ));

        // 分页查询应收账款数据
        int page = 0;
        boolean hasMore = true;
        while (hasMore) {
            int offset = page * PAGE_SIZE;
            String querySql = "SELECT QYGS, XSZZ, SHENGQU, SHIQU, QX, QCYE, LJXS, LJHK, YSYE, " +
                    "ZLFX0_60, ZLFX60_1, ZLFX1_2, ZLFX2_3, ZLFX3_4, ZLFX4_5, ZLFX5 " +
                    "FROM " + RECEIVABLE_DETAIL_TABLE + " " +
                    "WHERE DATE(RQ) = ? AND BKGS = ? " +
                    "LIMIT " + PAGE_SIZE + " OFFSET " + offset;

            LOGGER.info("应收账款数据查询第{}页，SQL: {}", page + 1, querySql);
            List<RowMap> maps = DBSql.getMaps(conn, querySql, lastDayOfMonth, bkgs);

            if (maps.isEmpty()) {
                hasMore = false;
                LOGGER.info("应收账款数据第{}页无数据，停止分页查询", page + 1);
            } else {
                ArrayList<BO> bos = new ArrayList<>();
                for (RowMap map : maps) {
                    String xszz = map.getString("XSZZ");
                    BO bo = new BO();
                    bo.set("YEARMONTH", yearMonth);
                    bo.set("BKGS", bkgs);
                    bo.set("QYGS", map.getString("QYGS"));
                    bo.set("GC", xszz);
                    bo.set("SQ", map.getString("SHENGQU"));
                    bo.set("CITY", map.getString("SHIQU"));
                    bo.set("QX", map.getString("QX"));
                    if (resultMap.containsKey(xszz)) {
                        Location location = resultMap.get(xszz);
                        bo.set("JD", location.getLongitude());
                        bo.set("WD", location.getLatitude());
                    }
                    bo.set("QCYE", map.getDouble("QCYE"));
                    bo.set("NFH", map.getDouble("LJXS"));
                    bo.set("NHK", map.getDouble("LJHK"));
                    bo.set("YSZE", map.getDouble("YSYE"));
                    bo.set("ZL60", map.getDouble("ZLFX0_60"));
                    bo.set("ZL60_1", map.getDouble("ZLFX60_1"));
                    bo.set("ZL1_2", map.getDouble("ZLFX1_2"));
                    bo.set("ZL2_3", map.getDouble("ZLFX2_3"));
                    bo.set("ZL3_4", map.getDouble("ZLFX3_4"));
                    bo.set("ZL4_5", map.getDouble("ZLFX4_5"));
                    bo.set("ZL5", map.getDouble("ZLFX5"));
                    bos.add(bo);
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
                        int end = Math.min(bos.size(), i + BATCH_SIZE);
                        List<BO> batchList = bos.subList(i, end);
                        SDK.getBOAPI().createDataBO(BO_EU_XS_YSZK, batchList, UserContext.fromUID("admin"));
                    }
                    totalCount += bos.size();
                    LOGGER.info("应收账款数据第{}页处理完成，本页{}条记录，累计{}条", page + 1, bos.size(), totalCount);
                }
                page++;
            }
        }
        LOGGER.info("应收账款数据处理完成，共处理{}条记录", totalCount);
    }

    /**
     * 处理区域两金占比数据（分页查询）
     */
    private void processRegionTwoFundsRatio(Connection conn, String yearMonth, String bkgs) throws Exception {
        LOGGER.info("开始处理区域两金占比数据，年月: {}, 板块公司: {}", yearMonth, bkgs);
        int totalCount = 0;

        // 删除已存在的记录
        String deleteSql = "DELETE FROM " + BO_EU_XS_QYLJZB + " WHERE YEARMONTH = ? AND BKGS = ?";
        try {
            int deleted = DBSql.update(conn, deleteSql, new Object[]{yearMonth, bkgs});
            LOGGER.info("区域两金占比-已删除{}条记录", deleted);
        } catch (Exception e) {
            LOGGER.error("区域两金占比-删除{}数据错误，删除sql为：{}，请检查数据库链接：{}", bkgs, deleteSql, e.getMessage());
            throw e;
        }

        // 获取指定年月最后一天
        Calendar cal = Calendar.getInstance();
        cal.setTime(YEAR_MONTH_FORMAT.parse(yearMonth));
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        Date lastDayOfMonthDate = cal.getTime();
        String lastDayOfMonth = DATE_FORMAT.format(lastDayOfMonthDate);

        // 获取当前日期
        Calendar todayCal = Calendar.getInstance();
        todayCal.set(Calendar.HOUR_OF_DAY, 0);
        todayCal.set(Calendar.MINUTE, 0);
        todayCal.set(Calendar.SECOND, 0);
        todayCal.set(Calendar.MILLISECOND, 0);
        Date today = todayCal.getTime();

        // 比较日期 否则保持不变
        if (lastDayOfMonthDate.after(today)) {
            // 如果月末日期大于今天，使用今天日期
            lastDayOfMonth = DATE_FORMAT.format(today);
        }


        // 分页查询区域两金占比数据
        int page = 0;
        boolean hasMore = true;
        while (hasMore) {
            int offset = page * PAGE_SIZE;

            // 第一个SQL：查询应收账款数据
            String receivableSql = "SELECT QYGS, BKGS, YSYE as YSZK " +
                    "FROM " + RECEIVABLE_DETAIL_TABLE + " " +
                    "WHERE RQ = ? AND BKGS = ? " +
                    "GROUP BY QYGS, BKGS " +
                    "LIMIT " + PAGE_SIZE + " OFFSET " + offset;

            LOGGER.info("应收账款数据查询第{}页，SQL: {}", page + 1, receivableSql);
            List<RowMap> receivableMaps = DBSql.getMaps(conn, receivableSql, lastDayOfMonth, bkgs);

            if (receivableMaps.isEmpty()) {
                hasMore = false;
                LOGGER.info("应收账款数据第{}页无数据，停止分页查询", page + 1);
            } else {
                ArrayList<BO> bos = new ArrayList<>();

                // 收集所有销售组织用于库存查询
                List<String> xszzList = new ArrayList<>();
                Map<String, RowMap> receivableMap = new HashMap<>();

                for (RowMap map : receivableMaps) {
                    String qygs = map.getString("QYGS");
                    List<RowMap> maps = DBSql.getMaps("SELECT * FROM BO_EU_BNBM_QYGSDYB WHERE QYGS = '" + qygs + "'");
                    for (RowMap rowMap : maps) {
                        String xszz = rowMap.getString("XSZZ");
                        xszzList.add(xszz);
                        receivableMap.put(xszz, map);
                    }
                }

                // 第二个SQL：查询库存金额数据
                if (!xszzList.isEmpty()) {
                    String placeholders = String.join(",", Collections.nCopies(xszzList.size(), "?"));
                    String inClause = xszzList.stream()
                            .map(s -> "'" + s.replace("'", "''") + "'") // 转义单引号防止SQL注入
                            .collect(Collectors.joining(","));

                    String inventorySql = "SELECT STOCKORGNAME, SUM(BALANCE_AMOUNT) as KCJE " +
                            "FROM " + BO_EU_DWD_ORDER_KC_HZ + " " +
                            "WHERE STOCKORGNAME IN (" + inClause + ") " +
                            "AND CATEGORY = '产成品' " +
                            "AND YEAR(INDATE) = YEAR('"+lastDayOfMonth+"') " +
                            "AND MONTH(INDATE) = MONTH('"+lastDayOfMonth+"') " +
                            "GROUP BY STOCKORGNAME";

                    LOGGER.info("库存金额数据查询，SQL: {}", inventorySql);

                    List<RowMap> inventoryMaps = DBSql.getMaps(conn, inventorySql);
                    Map<String, Double> inventoryMap = inventoryMaps.stream()
                            .collect(Collectors.toMap(
                                    row -> row.getString("STOCKORGNAME"),
                                    row -> row.getDouble("KCJE"),
                                    (existing, replacement) -> existing
                            ));

                    // 合并数据并创建BO对象
                    for (RowMap receivable : receivableMaps) {
                        String xszz = receivable.getString("XSZZ");
                        double yszk = receivable.getDouble("YSZK");
                        double kcje = inventoryMap.getOrDefault(xszz, 0.0);

                        BO bo = new BO();
                        bo.set("YEARMONTH", yearMonth);
                        bo.set("BKGS", bkgs);
                        bo.set("QYGS", receivable.getString("QYGS"));
                        bo.set("YSZK", yszk);
                        bo.set("KCJE", kcje);
                        bos.add(bo);
                    }
                }

                // 批量新增BO
                if (!bos.isEmpty()) {
                    for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
                        int end = Math.min(bos.size(), i + BATCH_SIZE);
                        List<BO> batchList = bos.subList(i, end);
                        SDK.getBOAPI().createDataBO(BO_EU_XS_QYLJZB, batchList, UserContext.fromUID("admin"));
                    }
                    totalCount += bos.size();
                    LOGGER.info("区域两金占比数据第{}页处理完成，本页{}条记录，累计{}条",
                            page + 1, bos.size(), totalCount);
                }
                page++;
            }
        }
        LOGGER.info("区域两金占比数据处理完成，共处理{}条记录", totalCount);
    }

    /**
     * 获取两个日期之间的所有年月
     */
    private List<String> getYearMonthsBetweenDates(Date startDate, Date endDate) {
        List<String> yearMonths = new ArrayList<>();
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);
        startCal.set(Calendar.DAY_OF_MONTH, 1);

        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);
        endCal.set(Calendar.DAY_OF_MONTH, endCal.getActualMaximum(Calendar.DAY_OF_MONTH));

        Calendar currentCal = (Calendar) startCal.clone();

        while (!currentCal.after(endCal)) {
            yearMonths.add(YEAR_MONTH_FORMAT.format(currentCal.getTime()));
            currentCal.add(Calendar.MONTH, 1);
        }

        return yearMonths;
    }
}
