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.bpms.util.UtilDate;
import com.actionsoft.sdk.local.SDK;
import com.awspaas.user.apps.bnbm.datalinkup.entity.DateRange;
import com.awspaas.user.apps.bnbm.datalinkup.service.DataSummaryService;
import com.awspaas.user.apps.bnbm.datalinkup.util.SaleUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
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 SaleDataSummaryServiceImpl implements DataSummaryService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SaleDataSummaryServiceImpl.class);

    // 维度表名常量
    /**
     * 一体化_销售_产品配套率月度表
     */
    private static final String MATCHING_RATE_YEAR_TABLE = "BO_EU_DATALINKUP_FACT_MATCHING_RATE_YEAR";
    /**
     * 一体化_销售_产品销售月明细表
     */
    private static final String PRODUCT_MONTHLY_TABLE = "BO_EU_DATALINKUP_FACT_PRODUCT_MONTHLY";
    /**
     * 一体化_销售_应收账款品牌月明细表
     */
    private static final String RECEIVABLE_BRAND_MONTHLY_TABLE = "BO_EU_DATALINKUP_FACT_RECEIVABLE_BRAND_MONTHLY";
    /**
     * 一体化_销售_应收账款月度汇总表
     */
    private static final String RECEIVABLE_YEAR_TABLE = "BO_EU_DATALINKUP_FACT_RECEIVABLE_YEAR";
    /**
     * 一体化_销售_营业收入月度汇总
     */
    private static final String REVENUE_YEAR_TABLE = "BO_EU_DATALINKUP_FACT_REVENUE_YEAR";
    /**
     * 一体化_销售_产品单价日明细表
     */
    private static final String UNIT_PRICE_DAILY_TABLE = "BO_EU_DATALINKUP_FACT_UNIT_PRICE_DAILY";
    /**
     * 一体化_销售_净利润月度汇总
     */
    private static final String NET_PROFIT_MONTHLY_TABLE = "BO_EU_DATALINKUP_JLR_MONTH";

    // 原始数据表名
    /**
     * 销售_销售类_汇总表
     */
    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 SimpleDateFormat YEAR_MONTH_FORMAT = new SimpleDateFormat("yyyy-MM");
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    @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 ((!"龙牌,梦牌,泰山石膏,北新嘉宝莉,北新涂料".contains(bkgs))){
                LOGGER.error("主配置中板块公司为：{}，无需进行计算",bkgs);
                return;
            }
            if (dateRange == null || dateRange.getStartDate() == null || dateRange.getEndDate() == null) {
                LOGGER.info("未提供有效时间范围，按当前日期计算");
                Calendar cal = Calendar.getInstance();
                int year = cal.get(Calendar.YEAR);
                int month = cal.get(Calendar.MONTH) + 1;
                int day = cal.get(Calendar.DAY_OF_MONTH);
                String yearMonth = String.format("%04d-%02d", year, month);

                String startDate = DATE_FORMAT.format(cal.getTime());

                // 1. 计算并保存产品配套率年度数据(按月存储)
//                calculateAndSaveMatchingRate(year, month, yearMonth, bkgs);
                newcalculateAndSaveMatchingRate(startDate, yearMonth, bkgs);

                // 2. 计算并保存产品销售月明细数据
//                calculateAndSaveProductMonthly(year, month, yearMonth, bkgs);
                newcalculateAndSaveProductMonthly(startDate, yearMonth, bkgs);

                // 3. 计算并保存应收账款品牌月明细
//                calculateAndSaveReceivableBrandMonthly(year, month, yearMonth, bkgs);
                newcalculateAndSaveReceivableBrandMonthly(startDate, yearMonth, bkgs);

                // 4. 计算并保存应收账款年度汇总(按月存储)
//                calculateAndSaveReceivableYear(year, month, yearMonth, bkgs);
                newcalculateAndSaveReceivableYear(startDate, yearMonth, bkgs);

                // 5. 计算并保存营业收入年度汇总(按月存储)
                calculateAndSaveRevenueYear(startDate,year, month, yearMonth, bkgs);

                // 6. 计算并保存产品单价日明细
//                calculateAndSaveUnitPriceDaily(year, month, day, currentDate, bkgs);
                newcalculateAndSaveUnitPriceDaily(startDate,year, month, day, bkgs);
            } else {
                LOGGER.info("开始执行销售数据多维度汇总计算（时间范围: {} 至 {})",
                        dateRange.getStartDate(), dateRange.getEndDate());
                //从结束时间获取年月
                Calendar startCal = Calendar.getInstance();
                startCal.setTime(dateRange.getStartDate());
                startCal.set(Calendar.DAY_OF_MONTH, 1); // 设置为月份的第一天
                int year = startCal.get(Calendar.YEAR);
                int month = startCal.get(Calendar.MONTH) + 1;
                int day = startCal.get(Calendar.DAY_OF_MONTH);
                String yearMonth = String.format("%04d-%02d", year, month);

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

                // 计算并保存产品配套率年度数据(按月存储)
                newcalculateAndSaveMatchingRate(startDate, yearMonth, bkgs);
                // 计算并保存产品销售月明细数据
                newcalculateAndSaveProductMonthly(startDate, yearMonth, bkgs);
                // 计算并保存应收账款品牌月明细
                newcalculateAndSaveReceivableBrandMonthly(startDate, yearMonth, bkgs);
                // 计算并保存应收账款年度汇总(按月存储)
                newcalculateAndSaveReceivableYear(startDate, yearMonth, bkgs);
                // 计算并保存产品单价日明细
                newcalculateAndSaveUnitPriceDaily(startDate,year, month, day, bkgs);

                // 计算月度维度数据（按月遍历）
                calculateMonthlyData(dateRange, bkgs);


                // 计算日度维度数据（按天遍历）
//                calculateDailyData(dateRange, bkgs);

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

    /**
     * 计算并保存产品单价日明细
     * @param startDate
     * @param year
     * @param month
     * @param day
     * @param bkgs
     */
    private void newcalculateAndSaveUnitPriceDaily(String startDate, int year, int month, int day, String bkgs) {
        try {
            LOGGER.info("开始计算{}-{}-{}产品单价日明细数据", year, month, day);

            //新增前删除数据YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "AND DAY(DZRQ) = '"+day+"'
            int delete = DBSql.update("DELETE FROM " + UNIT_PRICE_DAILY_TABLE
                    + " WHERE DATE >= '" + startDate + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}-产品单价日明细数据，删除了{}条数据",startDate,delete);
            String sql = "SELECT " +
                    "    DZRQ, " +
                    "    LB_1, " +
                    "    LB_2, " +
                    "    LB_3, " +
                    "    BKGS, " +
                    "    CASE " +
                    "        WHEN SQ LIKE '%海南%' THEN '海南' " +
                    "        WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                    "        WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                    "    END AS PROVINCE, " +
                    "    CS, " +
                    "    SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE XSSL END) AS SALES_VOLUME, " +
                    "    SUM(NMNY) AS REVENUE_AMOUNT, " +
                    "    SUM(NMNY)  / SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE XSSL END) AS UNIT_PRICE " +
                    "FROM " +
                    "    BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                    "WHERE " +
                    "    LB_1 IN ('石膏板', '轻钢龙骨', '涂料') " +
                    "    AND DZRQ >= ? " +
                    "    AND BKGS = ? " +
                    "    AND (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                    "GROUP BY " +
                    "    DZRQ, LB_1, LB_2, LB_3, BKGS, SQ, CS " +
                    "ORDER BY " +
                    "    DZRQ";
            List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);
            if (maps!=null){
                // 循环外先获取下公装家装、基材面材类别
                List<BO> gzjzList = SDK.getBOAPI().query("BO_EU_DATALINKUP_CPJZGZJCMC").desc().list();
                ArrayList<BO> list = new ArrayList<>();
                for (RowMap map : maps) {
                    String bkgs1 = map.getString("BKGS");
                    String lb_1 = map.getString("LB_1");
                    String lb_2 = map.getString("LB_2");
                    String lb_3 = map.getString("LB_3");
                    String dzrq = map.getString("DZRQ");
                    String province = map.getString("PROVINCE");
                    String sales_volume = map.getString("SALES_VOLUME");
                    String revenue_amount = map.getString("REVENUE_AMOUNT");
                    String unit_price = map.getString("UNIT_PRICE");
                    BO priceBO = new BO();
                    priceBO.set("BKGS", bkgs1);
                    priceBO.set("DATE", dzrq);
                    priceBO.set("CITY", map.getString("CS"));
                    priceBO.set("PRODUCT_TYPE", lb_1);
                    priceBO.set("SALES_VOLUME", sales_volume);
                    priceBO.set("REVENUE_AMOUNT", revenue_amount);
                    priceBO.set("UNIT_PRICE", unit_price);
                    priceBO.set("SHENGQU", province);//省区
                    String[] gzjzStrings = SaleUtil.matchSingleField(bkgs, lb_1, lb_2,lb_3, gzjzList, "其他", "其他","其他");
                    priceBO.set("MC_JC", gzjzStrings[1]);//面材/基材
                    priceBO.set("JZ_GZ", gzjzStrings[0]);//家装/工装
                    priceBO.set("PROD_CAT", gzjzStrings[2]);//产品类型
                    priceBO.set("PBGNB", gzjzStrings[3]);//普板/功能板
                    priceBO.set("ISOEM", gzjzStrings[4]);//是否OEM板
                    String monthPeriod = SaleUtil.getMonthPeriod(dzrq);
                    priceBO.set("XUN", monthPeriod);//月寻
                    list.add(priceBO);
                }
                SDK.getBOAPI().createDataBO(UNIT_PRICE_DAILY_TABLE,list,UserContext.fromUID("admin"));

                //更新城市名称
                int update = DBSql.update("UPDATE" +
                        "                    BO_EU_DATALINKUP_FACT_UNIT_PRICE_DAILY a " +
                        "                    INNER JOIN " +
                        "                    BO_EU_YTH_CCJCWH b ON a.CITY = b.CS " +
                        "                    SET " +
                        "                    a.CITY_SHORT = b.CSJC");
                LOGGER.info("一体化产品单价日明细更新城市名称");
            }
            LOGGER.info("产品单价日明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品单价日明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存应收账款年度汇总(按月存储)
     * @param startDate
     * @param yearMonth
     * @param bkgs
     */
    private void newcalculateAndSaveReceivableYear(String startDate, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}应收账款累计数据", startDate);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + RECEIVABLE_YEAR_TABLE
                    + " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}-应收账款年度汇总(按月存储)，删除了{}条数据",startDate,delete);

            //分别遍历省份
            HashMap<String, String> sfMap = new HashMap<>();
            sfMap.put("新疆维吾尔自治区","SHENGQU IN ('新疆维吾尔自治区') ");
            sfMap.put("海南省","SHENGQU IN ('海南') ");
            sfMap.put("西藏自治区","SHENGQU IN ('西藏') ");
            sfMap.put("一体化","SHENGQU IN ('新疆维吾尔自治区', '海南', '西藏') ");
            for (String key : sfMap.keySet()) {
                // 获取省份简称
                String abbreviation = SaleUtil.getProvinceAbbreviation(key);
                String sfSql = sfMap.get(key);
                String sql = "SELECT CONCAT(YEAR(RQ), '-', LPAD(MONTH(RQ), 2, '0')) ASyear_month,BKGS," +
                        "    SUM(QCYE) AS QCYE,SUM(LJXS) AS LJXS,SUM(LJHK) AS LJHK,(SUM(QCYE) + SUM(LJXS) - SUM(LJHK)) AS receivable" +
                        " FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
                        " WHERE RQ >= ? AND BKGS = ?  AND "+sfSql+"" +
                        " GROUP BY YEAR(RQ), MONTH(RQ)" +
                        " ORDER BY YEAR(RQ), MONTH(RQ)";

                List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);

                //查询去年数据
                LocalDate localDate = LocalDate.parse(startDate).minusYears(1);
                String lastDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                List<RowMap> lastMaps = DBSql.getMaps(sql, lastDate, bkgs);
                Map<String, RowMap> resultMap = lastMaps.stream()
                        .filter(row -> row.getString("ASyear_month") != null) // 过滤掉键为 null 的条目
                        .collect(Collectors.toMap(
                                row -> row.getString("ASyear_month"),
                                row -> row,
                                (oldValue, newValue) -> newValue // 重复时取新值
                        ));

                if (maps!=null){
                    ArrayList<BO> list = new ArrayList<>();
                    for (RowMap map : maps) {
                        String aSyear_month = map.getString("ASyear_month");
                        BO bo = new BO();
                        bo.set("YEARMONTH",aSyear_month);//年月(YYYY-MM)
                        bo.set("BKGS",map.getString("BKGS"));//板块公司
//                    bo.set("RECEIVABLE_TYPE",map.getString(""));//应收类型(板骨/涂料)
                        bo.set("OPENING_BALANCE",map.getString("QCYE"));//期初余额(万元)
                        bo.set("CUMULATIVE_SALES",map.getString("LJXS"));//累计销售(万元)
                        bo.set("CUMULATIVE_REPAYMENT",map.getString("LJHK"));//累计回款(万元)
                        bo.set("ENDING_BALANCE",map.getString("receivable"));//期末余额(万元)
                        // 定义日期格式
                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
                        // 解析字符串为YearMonth对象
                        YearMonth current = YearMonth.parse(yearMonth, formatter);
                        // 获取上一年同月
                        YearMonth previous = current.minusYears(1);
                        String lastYearMonth = previous.format(formatter);
                        RowMap map1 = resultMap.get(lastYearMonth);
                        if (map1!=null){
                            double lastDou = StringUtils.isNotBlank(map1.getString("receivable"))?Double.parseDouble(map1.getString("receivable")):0;
                            BigDecimal last = BigDecimal.valueOf(lastDou);
                            double currentDou = StringUtils.isNotBlank(map.getString("receivable"))?Double.parseDouble(map.getString("receivable")):0;
                            BigDecimal bigDecimal = BigDecimal.valueOf(currentDou);
                            if (last == null || last.compareTo(BigDecimal.ZERO) == 0) {
                                bo.set("YOY_RATE",0.0);//同比变化率(%)
                            }else {
                                bo.set("YOY_RATE",bigDecimal.subtract(last)
                                        .divide(last, 4, RoundingMode.HALF_UP)
                                        .multiply(BigDecimal.valueOf(100)));//同比变化率(%)
                            }
                        }
                        bo.set("SHENGQU",abbreviation);//省区
                        list.add(bo);
                    }
                    SDK.getBOAPI().createDataBO(RECEIVABLE_YEAR_TABLE,list,UserContext.fromUID("admin"));
                }
            }
            LOGGER.info("应收账款月度累计数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("应收账款月度累计数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }

    }

    /**
     *
     * 计算并保存应收账款品牌月明细
     * @param startDate
     * @param yearMonth
     * @param bkgs
     */
    private void newcalculateAndSaveReceivableBrandMonthly(String startDate, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}应收账款品牌明细数据", yearMonth);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + RECEIVABLE_BRAND_MONTHLY_TABLE
                    + " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("{}：准备同步{}-应收账款品牌月明细，删除了{}条数据",bkgs,yearMonth,delete);

            //分别遍历省份
            HashMap<String, String> sfMap = new HashMap<>();
            sfMap.put("新疆维吾尔自治区","SHENGQU IN ('新疆维吾尔自治区') ");
            sfMap.put("海南省","SHENGQU IN ('海南') ");
            sfMap.put("西藏自治区","SHENGQU IN ('西藏') ");
            sfMap.put("一体化","SHENGQU IN ('新疆维吾尔自治区', '海南', '西藏') ");
            for (String key : sfMap.keySet()) {
                // 获取省份简称
                String abbreviation = SaleUtil.getProvinceAbbreviation(key);
                // 根据省份value值查询数据
                String sfSql = sfMap.get(key);
                String sql = "SELECT CONCAT(YEAR(t1.RQ), '-', LPAD(MONTH(t1.RQ), 2, '0')) ASyear_month,t1.BKGS AS BKGS, YEAR(t1.RQ) AS year,MONTH(t1.RQ) AS month,t1.SHENGQU,SUM(t1.YSYE) AS receivable " +
                        " FROM BO_EU_BNBM_DATALINKUP_XS_YSL t1 " +
                        " INNER JOIN (" +
                        "    SELECT MAX(RQ) AS max_rq,YEAR(RQ) AS year,MONTH(RQ) AS month " +
                        "    FROM BO_EU_BNBM_DATALINKUP_XS_YSL " +
                        "    WHERE RQ >= ? AND BKGS = ? AND "+sfSql+" " +
                        "    GROUP BY YEAR(RQ), MONTH(RQ) " +
                        ") t2 ON t1.RQ = t2.max_rq AND YEAR(t1.RQ) = t2.year AND MONTH(t1.RQ) = t2.month " +
                        " WHERE t1.BKGS = ? AND t1."+sfSql+" " +
                        " GROUP BY YEAR(t1.RQ),MONTH(t1.RQ),t1.SHENGQU " +
                        " ORDER BY year, month, t1.SHENGQU";

                List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs, bkgs);
                if (maps!=null){
                    ArrayList<BO> list = new ArrayList<>();
                    for (RowMap map : maps) {
                        BO bo = new BO();
                        bo.set("YEARMONTH",map.getString("ASyear_month"));//年月(YYYY-MM)
                        bo.set("BKGS",map.getString("BKGS"));//板块公司
                        bo.set("BRAND",map.getString("BKGS"));//品牌(龙牌/泰山/梦牌/北新/嘉宝莉)
                        bo.set("RECEIVABLE_AMOUNT",map.getString("receivable"));//应收账款余额(万元)
                        bo.set("SHENGQU",abbreviation);//省区
                        list.add(bo);
                    }
                    SDK.getBOAPI().createDataBO(RECEIVABLE_BRAND_MONTHLY_TABLE,list,UserContext.fromUID("admin"));
                }
            }
            LOGGER.info("应收账款品牌月明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("应收账款品牌月明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存产品销售月明细数据
     * @param startDate
     * @param yearMonth
     * @param bkgs
     */
    private void newcalculateAndSaveProductMonthly(String startDate, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}-产品销售明细数据", yearMonth);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + PRODUCT_MONTHLY_TABLE
                    + " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}-产品销售明细数据，删除了{}条数据",yearMonth,delete);

            //分别遍历省份
            HashMap<String, String> sfMap = new HashMap<>();
            sfMap.put("新疆维吾尔自治区","SQ LIKE '%新疆%'");
            sfMap.put("海南省","SQ LIKE '%海南%'");
            sfMap.put("西藏自治区","SQ LIKE '%西藏%'");
            sfMap.put("一体化","SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%'");
            for (String key : sfMap.keySet()) {
                // 获取省份简称
                String abbreviation = SaleUtil.getProvinceAbbreviation(key);
                // 根据省份value值查询数据
                String sfSql = sfMap.get(key);
                String sql = "SELECT BKGS,LB_1,LB_2 AS brand,CONCAT(YEAR, '-', LPAD(MONTH, 2, '0')) ASyear_month," +
                        " SUM(ZSSL) AS total_zssl, SUM(XSSL)/10000 AS total_xssl_10k, SUM(NMNY) AS total_ssjermb," +
                        " (SUM(ZSSL)/(SUM(SUM(ZSSL)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ)))) *100 AS lb1_month_zssl_total," +
                        " ((SUM(XSSL)/10000)/(SUM(SUM(XSSL)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ)) / 10000))*100 AS lb1_month_xssl_total_10k," +
                        " (SUM(NMNY)/(SUM(SUM(NMNY)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ))))*100 AS lb1_month_ssjermb_total" +
                        " FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                        " WHERE DZRQ>? AND BKGS = ? AND LB_1 IN('石膏板','轻钢龙骨','涂料') AND ("+sfSql+")  " +
                        " GROUP BY LB_2,year, month" +
                        " ORDER BY year, month";
                List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);
                ArrayList<BO> list = new ArrayList<>();
                if (maps!=null){
                    for (RowMap map : maps) {
                        String lb_1 = map.getString("LB_1");
                        String year_month = map.getString("ASyear_month");
                        String brand = map.getString("brand");

                        BO productBO = new BO();
                        productBO.set("BKGS", bkgs); // 新增BKGS字段
                        productBO.set("YEARMONTH", year_month);
                        if ("北新嘉宝莉".equals(bkgs) || "北新涂料".equals(bkgs)) {
                            if ("其他".equals(lb_1)){
                                productBO.set("PRODUCT_TYPE", "其他");
                            }else {
                                productBO.set("PRODUCT_TYPE", "涂料");
                            }
                        } else if ("石膏板".equals(lb_1) || "轻钢龙骨".equals(lb_1) ) {
                            productBO.set("PRODUCT_TYPE", lb_1);
                        } else {
                            productBO.set("PRODUCT_TYPE", "其他");
                        }
                        productBO.set("BRAND", brand);
                        // 设置销量及占比
                        if (bkgs.contains("泰山")){
                            productBO.set("SALES_VOLUME",map.getString("total_xssl_10k"));// 销售量
                            productBO.set("SALES_VOLUME_RATIO",map.getString("lb1_month_xssl_total_10k"));// 销量占比(%)
                        }else {
                            productBO.set("SALES_VOLUME",map.getString("total_zssl"));// 销售量
                            productBO.set("SALES_VOLUME_RATIO",map.getString("lb1_month_zssl_total"));// 销量占比(%)
                        }
                        productBO.set("REVENUE_AMOUNT",map.getString("total_ssjermb"));// 营业收入(万元)
                        productBO.set("REVENUE_RATIO",map.getString("lb1_month_ssjermb_total"));// 收入占比(%)
                        productBO.set("SHENGQU",abbreviation);// 省区
                        list.add(productBO);
                    }
                    SDK.getBOAPI().createDataBO(PRODUCT_MONTHLY_TABLE,list,UserContext.fromUID("admin"));
                }
            }

            LOGGER.info("产品销售月明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品销售月明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存产品配套率年度数据(按月存储)
     * @param startDate
     * @param yearMonth
     * @param bkgs
     */
    private void newcalculateAndSaveMatchingRate(String startDate, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}产品配套率数据", yearMonth);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + MATCHING_RATE_YEAR_TABLE
                    + " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("{}：准备同步{}产品配套率数据，删除了{}条数据",bkgs,yearMonth,delete);
            String querySql =" SELECT " +
                            "    DATE_FORMAT(DZRQ, '%Y-%m') AS YEARMONTH, " +
                            "    CASE " +
                            "        WHEN SQ LIKE '%海南%' THEN '海南' " +
                            "        WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                            "        WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                            "    END AS PROVINCE, " +
                            "    SUM(CASE WHEN LB_1 = '石膏板' THEN XSSL ELSE 0 END) AS gypsum_board_sales, " +
                            "    SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE 0 END) AS steel_keel_sales " +
                            " FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ  " +
                            " WHERE " +
                            "    (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                            "    AND DZRQ >= ? " +
                            "    AND LB_1 IN ('轻钢龙骨','石膏板') " +
                            "    AND BKGS = ? " +
                            " GROUP BY " +
                            "    PROVINCE, " +
                            "    YEARMONTH " +
                            " ORDER BY " +
                            "    YEARMONTH ASC, " +
                            "    PROVINCE ASC";
            List<RowMap> maps = DBSql.getMaps(querySql, startDate, bkgs);
            ArrayList<BO> list = new ArrayList<>();
            if (maps!=null) {
                for (RowMap map : maps) {
                    String year_Month = map.getString("YEARMONTH");
                    String province = map.getString("PROVINCE");
                    BO matchingRateBO = new BO();
                    matchingRateBO.set("YEARMONTH", year_Month);
                    matchingRateBO.set("BKGS", bkgs);
                    matchingRateBO.set("GYPSUM_SALES_VOLUME", map.getString("gypsum_board_sales"));
                    matchingRateBO.set("STEEL_SALES_VOLUME", map.getString("steel_keel_sales"));
                    matchingRateBO.set("SHENGQU", province);
                    list.add(matchingRateBO);
                }
            }
            // 保存数据
            SDK.getBOAPI().createDataBO(MATCHING_RATE_YEAR_TABLE,list,UserContext.fromUID("admin"));
            LOGGER.info("产品配套率月度累计数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品配套率月度累计数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }

    }

    /**
     * 按当前日期计算（无时间范围时使用）
     */
//    private void calculateForCurrentDate(String bkgs) {
//        Calendar cal = Calendar.getInstance();
//        int year = cal.get(Calendar.YEAR);
//        int month = cal.get(Calendar.MONTH) + 1;
//        int day = cal.get(Calendar.DAY_OF_MONTH);
//        String yearMonth = String.format("%04d-%02d", year, month);
//        Date currentDate = new Date(System.currentTimeMillis());
//
//        // 1. 计算并保存产品配套率年度数据(按月存储)
//        calculateAndSaveMatchingRate(year, month, yearMonth, bkgs);
//
//        // 2. 计算并保存产品销售月明细数据
//        calculateAndSaveProductMonthly(year, month, yearMonth, bkgs);
//
//        // 3. 计算并保存应收账款品牌月明细
//        calculateAndSaveReceivableBrandMonthly(year, month, yearMonth, bkgs);
//
//        // 4. 计算并保存应收账款年度汇总(按月存储)
//        calculateAndSaveReceivableYear(year, month, yearMonth, bkgs);
//
//        // 5. 计算并保存营业收入年度汇总(按月存储)
//        calculateAndSaveRevenueYear(year, month, yearMonth, bkgs);
//
//        // 6. 计算并保存产品单价日明细
//        calculateAndSaveUnitPriceDaily(year, month, day, currentDate, bkgs);
//    }

    /**
     * 计算月度维度数据
     */
    private void calculateMonthlyData(DateRange dateRange, String bkgs) {
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(dateRange.getStartDate());
        startCal.set(Calendar.DAY_OF_MONTH, 1); // 设置为月份的第一天
        String startDate = DATE_FORMAT.format(dateRange.getStartDate());
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(dateRange.getEndDate());
        endCal.set(Calendar.DAY_OF_MONTH, endCal.getActualMaximum(Calendar.DAY_OF_MONTH)); // 设置为月份的最后一天
        int year = startCal.get(Calendar.YEAR);
        int month = startCal.get(Calendar.MONTH) + 1;
        Calendar monthCal = (Calendar) startCal.clone();
        String yearMonth = String.format("%04d-%02d", year, month);
        calculateAndSaveRevenueYear(startDate,year, month, yearMonth, bkgs);
    }

    /**
     * 计算日度维度数据
     */
    private void calculateDailyData(DateRange dateRange, String bkgs) {
        Calendar dayCal = Calendar.getInstance();
        dayCal.setTime(dateRange.getStartDate());

        Calendar endCal = Calendar.getInstance();
        endCal.setTime(dateRange.getEndDate());

        while (!dayCal.after(endCal)) {
            int year = dayCal.get(Calendar.YEAR);
            int month = dayCal.get(Calendar.MONTH) + 1;
            int day = dayCal.get(Calendar.DAY_OF_MONTH);
            Date currentDate = dayCal.getTime();

            LOGGER.info("计算日度汇总数据: {}-{}-{}", year, month, day);

            // 6. 产品单价日明细
            calculateAndSaveUnitPriceDaily(year, month, day, currentDate, bkgs);

            // 下一天
            dayCal.add(Calendar.DATE, 1);
        }
    }

    // ==================== 各维度计算方法 ====================

    /**
     * 计算并保存产品配套率年度数据(按月存储)
     * 板骨配套率 = 石膏板销售数量 / 轻钢龙骨销售数量
     */
    private void calculateAndSaveMatchingRate(int year, int month, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}年{}月产品配套率数据", year, month);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + MATCHING_RATE_YEAR_TABLE
                    + " WHERE YEARMONTH = '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}年{}月产品配套率数据，删除了{}条数据",year, month,delete);

            // 获取石膏板年度销售量（万平方米） - 从当年1月到当前月
            BigDecimal gypsumSales = getSalesToMonth(year, month, "石膏板", bkgs);
            // 获取轻钢龙骨年度销售量（吨） - 从当年1月到当前月
            BigDecimal keelSales = getSalesToMonth(year, month, "轻钢龙骨", bkgs);

            // 计算板骨配套率（保留4位小数）
            BigDecimal ratio = BigDecimal.ZERO;
            if (keelSales.compareTo(BigDecimal.ZERO) != 0) {
                // 使用精确除法并设置舍入模式
                ratio = gypsumSales.divide(keelSales, 4, RoundingMode.HALF_UP);
            }

            // 创建BO对象并填充数据
            BO matchingRateBO = createBaseBO(bkgs);
            matchingRateBO.set("YEARMONTH", yearMonth);
            matchingRateBO.set("GYPSUM_SALES_VOLUME", gypsumSales.setScale(2, RoundingMode.HALF_UP));
            matchingRateBO.set("STEEL_SALES_VOLUME", keelSales.setScale(2, RoundingMode.HALF_UP));
            matchingRateBO.set("MATCHING_RATE", ratio.setScale(4, RoundingMode.HALF_UP));

            // 保存数据
            saveSummaryData(matchingRateBO, MATCHING_RATE_YEAR_TABLE);
            LOGGER.info("产品配套率月度累计数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品配套率月度累计数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存产品销售月明细数据
     * 包含石膏板和轻钢龙骨的销量、营收及占比计算
     */
    private void calculateAndSaveProductMonthly(int year, int month, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}年{}月-产品销售明细数据", year, month);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + PRODUCT_MONTHLY_TABLE
                    + " WHERE YEARMONTH = '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}年{}月-产品销售明细数据，删除了{}条数据",year, month,delete);

//            List<RowMap> maps = DBSql.getMaps("SELECT LB_1 FROM " + SALES_DETAIL_TABLE + " WHERE BKGS = '" + bkgs + "'" +
//                    "AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%') " + // 模糊查询
//                    " GROUP BY LB_1");
            String[] lb1s = new String[]{"石膏板","轻钢龙骨","涂料"};
            for (String lb_1 : lb1s) {
//                String lb_1 = map.getString("LB_1");
                processProductData(lb_1, year, month, yearMonth, bkgs);
            }
            LOGGER.info("产品销售月明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品销售月明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 处理指定产品的月明细数据
     * 计算各品牌的销量/营收总量、占比
     */
    private void processProductData(String productType, int year, int month, String yearMonth, String bkgs) {
        try {
            // 获取销量数据
            Map<String, BigDecimal> salesMap = getMonthlyData(year, month, productType, "sales", bkgs);
            BigDecimal totalSales = calculateTotal(salesMap);

            // 获取营收数据
            Map<String, BigDecimal> revenueMap = getMonthlyData(year, month, productType, "revenue", bkgs);
            BigDecimal totalRevenue = calculateTotal(revenueMap);

            // 为每个品牌创建记录
            for (String brand : salesMap.keySet()) {
                BO productBO = createBaseBO(bkgs);
                productBO.set("YEARMONTH", yearMonth);
                if ("北新嘉宝莉".equals(bkgs) || "北新涂料".equals(bkgs)) {
                    if ("其他".equals(productType)){
                        productBO.set("PRODUCT_TYPE", "其他");
                    }else {
                        productBO.set("PRODUCT_TYPE", "涂料");
                    }
                } else if ("石膏板".equals(productType) || "轻钢龙骨".equals(productType) ) {
                    productBO.set("PRODUCT_TYPE", productType);
                } else {
                    productBO.set("PRODUCT_TYPE", "其他");
                }
                productBO.set("BRAND", brand);

                // 设置销量及占比
                BigDecimal brandSales = salesMap.get(brand);
                productBO.set("SALES_VOLUME", brandSales.setScale(2, RoundingMode.HALF_UP));

                // 计算销量占比（百分比，保留2位小数）
                if (totalSales.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal salesRatio = brandSales.divide(totalSales, 4, RoundingMode.HALF_UP)
                            .multiply(BigDecimal.valueOf(100));
                    productBO.set("SALES_VOLUME_RATIO", salesRatio.setScale(2, RoundingMode.HALF_UP));
                } else {
                    productBO.set("SALES_VOLUME_RATIO", BigDecimal.ZERO);
                }

                // 设置营收及占比
                BigDecimal brandRevenue = revenueMap.get(brand);
                productBO.set("REVENUE_AMOUNT", brandRevenue.setScale(2, RoundingMode.HALF_UP));

                // 计算营收占比（百分比，保留2位小数）
                if (totalRevenue.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal revenueRatio = brandRevenue.divide(totalRevenue, 4, RoundingMode.HALF_UP)
                            .multiply(BigDecimal.valueOf(100));
                    productBO.set("REVENUE_RATIO", revenueRatio.setScale(2, RoundingMode.HALF_UP));
                } else {
                    productBO.set("REVENUE_RATIO", BigDecimal.ZERO);
                }

                saveSummaryData(productBO, PRODUCT_MONTHLY_TABLE);
            }
        } catch (Exception e) {
            String errorMsg = String.format("处理产品[%s]月明细数据失败: %s", productType, e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存应收账款品牌月明细
     * 区分板骨（龙牌/泰山/梦牌）和涂料（北新涂料/嘉宝莉）
     */
    private void calculateAndSaveReceivableBrandMonthly(int year, int month, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}年{}月应收账款品牌明细数据", year, month);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + RECEIVABLE_BRAND_MONTHLY_TABLE
                    + " WHERE YEARMONTH = '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}年{}月-应收账款品牌月明细，删除了{}条数据",year, month,delete);

            // 处理应收账款
            processReceivableData(getBoneReceivable(year, month, bkgs), yearMonth, bkgs);
            // 处理涂料应收账款
//            processReceivableData(getPaintReceivable(year, month, bkgs), yearMonth, bkgs);

            LOGGER.info("应收账款品牌月明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("应收账款品牌月明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 处理指定产品线的应收账款数据
     */
    private void processReceivableData(Map<String, BigDecimal> dataMap, String yearMonth, String bkgs) {
        try {
            for (Map.Entry<String, BigDecimal> entry : dataMap.entrySet()) {
                BO receivableBO = createBaseBO(bkgs);
                receivableBO.set("YEARMONTH", yearMonth);
//                receivableBO.set("PRODUCT_LINE", productLine);
                receivableBO.set("BRAND", entry.getKey());
                receivableBO.set("RECEIVABLE_AMOUNT", entry.getValue().setScale(2, RoundingMode.HALF_UP));
                saveSummaryData(receivableBO, RECEIVABLE_BRAND_MONTHLY_TABLE);
            }
        } catch (Exception e) {
            String errorMsg = String.format("处理板块[%s]应收账款失败: %s", bkgs, e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 计算并保存应收账款年度汇总(按月存储)
     * 应收账款 = 期初余额 + 累计销售 - 累计回款
     */
    private void calculateAndSaveReceivableYear(int year, int month, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}年{}月应收账款累计数据", year, month);

            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + RECEIVABLE_YEAR_TABLE
                    + " WHERE YEARMONTH = '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}年{}月-应收账款年度汇总(按月存储)，删除了{}条数据",year, month,delete);

            int lastYear = year - 1;
            int lastYearMonth = month; // 去年同月

            // 获取板块应收账款数据 - 当前月最新一天数据
            RowMap bkgsYsRowMap = getReceivableToMonth(year, month, bkgs);
            double qcye = bkgsYsRowMap.getDouble("QCYE");
            double ljxs = bkgsYsRowMap.getDouble("LJXS");
            double ljhk = bkgsYsRowMap.getDouble("LJHK");
            double receivable = bkgsYsRowMap.getDouble("receivable");
            // 获取去年同期的板骨应收账款数据 - 去年1月到去年同月
            RowMap bkgsYsLastYearRowMap = getReceivableToMonth(lastYear, lastYearMonth, bkgs);
            double receivableLastYear = bkgsYsLastYearRowMap.getDouble("receivable");
            BigDecimal boneYoy = calculateYoy(BigDecimal.valueOf(receivable), BigDecimal.valueOf(receivableLastYear));//同比

            // 保存板块数据
            saveReceivableYearData(yearMonth, BigDecimal.valueOf(qcye), BigDecimal.valueOf(ljxs),
                    BigDecimal.valueOf(ljhk), BigDecimal.valueOf(receivable), boneYoy, bkgs);

            LOGGER.info("应收账款月度累计数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("应收账款月度累计数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 保存应收账款月度累计数据
     */
    private void saveReceivableYearData(String yearMonth,BigDecimal qcye, BigDecimal ljxs, BigDecimal ljhk,
                                        BigDecimal total, BigDecimal yoy, String bkgs) {
        BO receivableBO = createBaseBO(bkgs);
        receivableBO.set("YEARMONTH", yearMonth);
//        receivableBO.set("RECEIVABLE_TYPE", type);
        receivableBO.set("OPENING_BALANCE",qcye.setScale(2, RoundingMode.HALF_UP));
        receivableBO.set("CUMULATIVE_SALES",ljxs.setScale(2, RoundingMode.HALF_UP));
        receivableBO.set("CUMULATIVE_REPAYMENT",ljhk.setScale(2, RoundingMode.HALF_UP));
        receivableBO.set("ENDING_BALANCE", total.setScale(2, RoundingMode.HALF_UP)); // 期末余额
        receivableBO.set("YOY_RATE", yoy.setScale(2, RoundingMode.HALF_UP));
        saveSummaryData(receivableBO, RECEIVABLE_YEAR_TABLE);
    }

    /**
     * 计算并保存营业收入年度汇总(按月存储)
     * 营业收入总量 = 石膏板 + 轻钢龙骨 + 涂料
     * 同比 = (当年营收 - 去年营收) / 去年营收 * 100%
     */
    private void calculateAndSaveRevenueYear(String startDate,int year, int month, String yearMonth, String bkgs) {
        try {
            LOGGER.info("开始计算{}年{}月营业收入累计数据", year, month);
            // 构造月份的两位格式（如1月转为"01"，10月保持"10"）
            String monthStr = String.format("%02d", month);
            //新增前删除数据
            int delete = DBSql.update("DELETE FROM " + REVENUE_YEAR_TABLE
                    + " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}年{}月-营业收入累计数据，删除了{}条数据",year, month,delete);
            //计算轻钢龙骨和石膏板
            /*String querySql = " SELECT " +
                    " BKGS, " +
                    " CASE WHEN LB_1 LIKE '%涂料%' THEN '涂料' ELSE LB_1 END AS LB_1, " +
                    " CASE " +
                    "   WHEN SQ LIKE '%海南%' THEN '海南' " +
                    "   WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                    "   WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                    " END AS PROVINCE, " +
                    " DATE_FORMAT(DZRQ, '%Y-%m') AS YEARMONTH, " +
                    " SUM(NMNY) AS REVENUE_AMOUNT " +
                    " FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                    " WHERE " +
                    "   (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                    "   AND DZRQ >= ? " +
                    "   AND BKGS = ? " +
                    "   AND (LB_1 IN ('石膏板', '轻钢龙骨')  OR LB_1 LIKE '%涂料%') " +
                    " GROUP BY " +
                    "   BKGS, " +
                    "   LB_1, " +
                    "   CASE " +
                    "       WHEN SQ LIKE '%海南%' THEN '海南' " +
                    "       WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                    "       WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                    "   END, " +
                    "   DATE_FORMAT(DZRQ, '%Y-%m') " +

                    " UNION ALL " +

                    " SELECT " +
                    " BKGS, " +
                    " CASE WHEN LB_1 LIKE '%涂料%' THEN '涂料' ELSE LB_1 END AS LB_1, " +
                    " '一体化' AS PROVINCE, " +
                    " DATE_FORMAT(DZRQ, '%Y-%m') AS YEARMONTH, " +
                    " SUM(NMNY) AS REVENUE_AMOUNT " +
                    " FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                    " WHERE " +
                    "   (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                    "   AND DZRQ >= ? " +
                    "   AND BKGS = ? " +
                    "   AND (LB_1 IN ('石膏板', '轻钢龙骨')  OR LB_1 LIKE '%涂料%') " +
                    "GROUP BY " +
                    "   BKGS, " +
                    "   LB_1, " +
                    "'一体化', " +
                    "   DATE_FORMAT(DZRQ, '%Y-%m') " +
                    "ORDER BY " +
                    "   YEARMONTH ASC, " +
                    "   PROVINCE ASC, " +
                    "   LB_1 ASC";*/

            String querySql =
                    "SELECT " +
                            "  BKGS, " +
                            "  CASE WHEN LB_1 LIKE '%涂料%' THEN '涂料' ELSE LB_1 END AS LB_1, " +
                            "  CASE " +
                            "    WHEN SQ LIKE '%海南%' THEN '海南' " +
                            "    WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                            "    WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                            "  END AS PROVINCE, " +
                            "  DATE_FORMAT(DZRQ, '%Y-%m') AS YEARMONTH, " +
                            "  SUM(NMNY) AS REVENUE_AMOUNT " +
                            "FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                            "WHERE " +
                            "  (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                            "  AND DZRQ >= ? " +
                            "  AND BKGS = ? " +
                            "  AND (" +
                            "    LB_1 IN ('石膏板', '轻钢龙骨') " +
                            "    OR (" +
                            "      ? IN ('北新嘉宝莉', '北新涂料') " +
                            "      AND LB_1 LIKE '%涂料%' " +
                            "    ) " +
                            "  ) " +
                            "GROUP BY " +
                            "  BKGS, " +
                            "  LB_1, " +
                            "  CASE " +
                            "    WHEN SQ LIKE '%海南%' THEN '海南' " +
                            "    WHEN SQ LIKE '%新疆%' THEN '新疆' " +
                            "    WHEN SQ LIKE '%西藏%' THEN '西藏' " +
                            "  END, " +
                            "  DATE_FORMAT(DZRQ, '%Y-%m') " +
                            "UNION ALL " +
                            "SELECT " +
                            "  BKGS, " +
                            "  CASE WHEN LB_1 LIKE '%涂料%' THEN '涂料' ELSE LB_1 END AS LB_1, " +
                            "  '一体化' AS PROVINCE, " +
                            "  DATE_FORMAT(DZRQ, '%Y-%m') AS YEARMONTH, " +
                            "  SUM(NMNY) AS REVENUE_AMOUNT " +
                            "FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
                            "WHERE " +
                            "  (SQ LIKE '%海南%' OR SQ LIKE '%新疆%' OR SQ LIKE '%西藏%') " +
                            "  AND DZRQ >= ? " +
                            "  AND BKGS = ? " +
                            "  AND (" +
                            "    LB_1 IN ('石膏板', '轻钢龙骨') " +
                            "    OR (" +
                            "      ? IN ('北新嘉宝莉', '北新涂料') " +
                            "      AND LB_1 LIKE '%涂料%' " +
                            "    ) " +
                            "  ) " +
                            "GROUP BY " +
                            "  BKGS, " +
                            "  LB_1, " +
                            "  '一体化', " +
                            "  DATE_FORMAT(DZRQ, '%Y-%m') " +
                            "ORDER BY " +
                            "  YEARMONTH ASC, " +
                            "  PROVINCE ASC, " +
                            "  LB_1 ASC";
            List<RowMap> rowMaps = DBSql.getMaps(querySql, startDate,bkgs,bkgs,startDate,bkgs,bkgs);
            LOGGER.info("板块公司：{}，本次查询数据：{}",bkgs,rowMaps.size());
            // 保存数据
            List<BO> list = new ArrayList<>();
            // 插入所有数据
            addSummaryData(list, rowMaps,bkgs);
            SDK.getBOAPI().createDataBO(REVENUE_YEAR_TABLE,list,UserContext.fromUID("admin"));
            LOGGER.info("营业收入月度累计数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("营业收入月度累计数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 保存营业收入月度累计数据
     */
    private void saveRevenueYearData(String yearMonth, String category,
                                     BigDecimal currentRevenue, BigDecimal lastRevenue, String bkgs,String abbreviation) {
        BigDecimal yoy = calculateYoy(currentRevenue, lastRevenue);

        BO revenueBO = createBaseBO(bkgs);
        revenueBO.set("YEARMONTH", yearMonth);
        if ("北新嘉宝莉".equals(bkgs)){
            if ("其他".equals(category)){
                revenueBO.set("PRODUCT_CATEGORY", category);
            }else {
                revenueBO.set("PRODUCT_CATEGORY", "涂料");
            }
        } else if ("石膏板".equals(category) || "轻钢龙骨".equals(category)) {
            revenueBO.set("PRODUCT_CATEGORY", category);
        }else {
            revenueBO.set("PRODUCT_CATEGORY", "其他");
        }

        revenueBO.set("REVENUE_AMOUNT", currentRevenue.setScale(2, RoundingMode.HALF_UP));
        revenueBO.set("YOY_RATE", yoy.setScale(2, RoundingMode.HALF_UP));
        revenueBO.set("SHENGQU", abbreviation);//省区
        saveSummaryData(revenueBO, REVENUE_YEAR_TABLE);
    }

    /**
     * 计算并保存产品单价日明细
     * 单价 = 营业收入 / 销售数量
     */
    private void calculateAndSaveUnitPriceDaily(int year, int month, int day, Date date, String bkgs) {
        try {
            LOGGER.info("开始计算{}-{}-{}产品单价日明细数据", year, month, day);

            //新增前删除数据YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "AND DAY(DZRQ) = '"+day+"'
            int delete = DBSql.update("DELETE FROM " + UNIT_PRICE_DAILY_TABLE
                    + " WHERE YEAR(DATE) = '" + year + "' AND MONTH(DATE) = '"+month+"' AND DAY(DATE) = '"+day+"' AND BKGS = '"+bkgs+"'");
            LOGGER.info("准备同步{}-产品单价日明细数据，删除了{}条数据",date,delete);

            String[] lb1s = new String[]{"石膏板","轻钢龙骨","涂料"};
            for (String lb_1 : lb1s) {
//                String lb_1 = map.getString("LB_1");
                saveUnitPriceData(date, lb_1, year, month, day, bkgs);
            }

            LOGGER.info("产品单价日明细数据保存成功");
        } catch (Exception e) {
            String errorMsg = String.format("产品单价日明细数据计算失败: %s", e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    /**
     * 保存产品单价数据（支持日/月计算）
     */
    private void saveUnitPriceData(Date date, String productType, int year, int month, int day, String bkgs) {
        try {
            // 获取销量和营收
            Object[] params = {year, month, productType, bkgs};
            String sql = "";
            if (bkgs.contains("龙牌")) {
                sql = "SELECT SUM(ZSSL)*10000 AS sales, SUM(SSJERMB) AS revenue " +
                        "FROM " + SALES_DETAIL_TABLE + " " +
                        "WHERE YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "' AND LB_1 = '" + productType + "' AND BKGS = '" + bkgs + "'" +
                        "AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%')"; // 模糊查询
            } else if (bkgs.contains("泰山")) {
                sql = "SELECT SUM(XSSL) AS sales, SUM(SSJERMB) AS revenue " +
                        "FROM " + SALES_DETAIL_TABLE + " " +
                        "WHERE YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "' AND LB_1 = '" + productType + "' AND BKGS = '" + bkgs + "'" +
                        "AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%')"; // 模糊查询
            }else {
                sql = "SELECT SUM(ZSSL) AS sales, SUM(SSJERMB) AS revenue " +
                        "FROM " + SALES_DETAIL_TABLE + " " +
                        "WHERE YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "' AND LB_1 = '" + productType + "' AND BKGS = '" + bkgs + "'" +
                        "AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%')"; // 模糊查询
            }

            if (day > 0) {
                sql += " AND DAY(DZRQ) = '"+day+"'";
            }

            RowMap result = DBSql.getMap(sql);
            System.out.println("result = " + result);
            if (result != null && result.get("sales") != null && result.get("revenue") != null) {
                BigDecimal sales = BigDecimal.valueOf(result.getDouble("sales"));
                BigDecimal revenue = BigDecimal.valueOf(result.getDouble("revenue"));
                BigDecimal unitPrice = BigDecimal.ZERO;

                // 计算单价（避免除零错误）
                if (sales.compareTo(BigDecimal.ZERO) > 0) {
                    // 石膏板单位转换：万元/万平方米 → 元/平方米
                    if ("石膏板".equals(productType)) {
                        unitPrice = revenue.divide(sales, 4, RoundingMode.HALF_UP);
                    }
                    // 轻钢龙骨单位：元/吨
//                    else
                    if ("轻钢龙骨".equals(productType)) {
                        unitPrice = revenue.divide(sales, 2, RoundingMode.HALF_UP);
                    }
                }

                BO priceBO = createBaseBO(bkgs);
                priceBO.set("DATE", new Timestamp(date.getTime()));
                if ("北新嘉宝莉".equals(bkgs)) {
                    priceBO.set("PRODUCT_TYPE", "涂料");
                }else {
                    priceBO.set("PRODUCT_TYPE", productType);
                }
                priceBO.set("SALES_VOLUME", sales.setScale(2, RoundingMode.HALF_UP));
                priceBO.set("REVENUE_AMOUNT", revenue.setScale(2, RoundingMode.HALF_UP));
                priceBO.set("UNIT_PRICE", unitPrice.setScale(2, RoundingMode.HALF_UP));
                saveSummaryData(priceBO, UNIT_PRICE_DAILY_TABLE);
            } else {
                LOGGER.warn("未找到{}-{}-{}的{}销售数据", year, month, day, productType);
            }
        } catch (Exception e) {
            String errorMsg = String.format("计算产品[%s]单价失败: %s", productType, e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }

    // ==================== 工具方法 ====================

    /**
     * 创建基础BO对象（填充公共字段）
     */
    private BO createBaseBO(String bkgs) {
        BO bo = new BO();
        bo.set("BKGS", bkgs); // 新增BKGS字段
        return bo;
    }

    /**
     * 计算同比变化率
     * 公式：(当期 - 同期) / 同期 * 100%
     */
    private BigDecimal calculateYoy(BigDecimal current, BigDecimal last) {
        if (last == null || last.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return current.subtract(last)
                .divide(last, 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
    }

    /**
     * 计算总值
     */
    private BigDecimal calculateTotal(Map<String, BigDecimal> dataMap) {
        return dataMap.values().stream()
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    // ==================== 数据访问方法 ====================

    /**
     * 获取产品从1月到指定月份的累计销售量
     */
    private BigDecimal getSalesToMonth(int year, int month, String productType, String bkgs) {
        String sql = "SELECT SUM(ZSSL) AS sales " +
                "FROM " + SALES_DETAIL_TABLE + " " +
                "WHERE YEAR(DZRQ) = '"+year+"' AND MONTH(DZRQ) BETWEEN 1 AND '"+month+"' AND LB_1 = '"+productType+"' AND BKGS = '"+bkgs+"'" +
                "AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%')"; // 模糊查询
        double value = DBSql.getDouble(sql, "sales");
        return BigDecimal.valueOf(value);
    }

    /**
     * 获取产品从1月到指定月份的累计营收
     */
    private BigDecimal getRevenueToMonth(int year, int month, String category, String bkgs, String sfSql) {
        String sql = "SELECT SUM(SSJERMB) AS revenue " +
                "FROM " + SALES_DETAIL_TABLE + " " +
                "WHERE YEAR(DZRQ) = '"+year+"' AND MONTH(DZRQ) = '"+month+"' AND LB_1 LIKE '%"+category+"%' AND BKGS = '"+bkgs+"'"+
                "AND ("+sfSql+")"; // 模糊查询
        double value = DBSql.getDouble(sql, "revenue");
        return BigDecimal.valueOf(value);
    }

    /**
     * 获取应收账款从1月到指定月份的累计值
     * 公式：期初余额 + 累计销售 - 累计回款
     */
    private RowMap getReceivableToMonth(int year, int month, String bkgs) {

        StringBuilder sql = new StringBuilder("SELECT SUM(QCYE) AS QCYE, SUM(LJXS) AS LJXS , SUM(LJHK) AS LJHK, (SUM(QCYE) + SUM(LJXS) - SUM(LJHK)) AS receivable")
                .append(" FROM " + RECEIVABLE_DETAIL_TABLE)
                .append(" WHERE RQ = ( SELECT MAX(RQ) FROM "+RECEIVABLE_DETAIL_TABLE+
                        " WHERE YEAR(RQ) = '"+year+"' AND MONTH(RQ) = '"+month+"'  AND BKGS = '"+bkgs+"' ) ")
                .append(" AND BKGS ='"+bkgs+"'");

        RowMap receivable = DBSql.getMap(sql.toString());
        return receivable;
    }

    /**
     * 获取月维度产品数据（销量/营收）
     */
    private Map<String, BigDecimal> getMonthlyData(int year, int month, String productType, String dataType, String bkgs) {
        String field = "";
        if (bkgs.contains("泰山")){
            if ("sales".equals(dataType)){
                if ("轻钢龙骨".equals(productType)){
                    field = " SUM(ZSSL) ";
                } else if ("石膏板".equals(productType)) {
                    field = " SUM(XSSL)/10000 ";
                }else {
                    field = " SUM(ZSSL) ";
                }
            }else {
                field = " SUM(SSJERMB) ";
            }
        }else {
            field = "sales".equals(dataType) ? "SUM(ZSSL)" : "SUM(SSJERMB)";

        }
        String sql = "SELECT LB_2 AS brand, " + field + " AS value " +
                " FROM " + SALES_DETAIL_TABLE + " " +
                " WHERE YEAR(DZRQ) = ? AND MONTH(DZRQ) = ? AND LB_1 = ? AND BKGS = ? " +
                " AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%') " + // 模糊查询
                " GROUP BY LB_2";
        Map<String, BigDecimal> result = new HashMap<>();
        List<RowMap> rows = DBSql.getMaps(sql, year, month, productType, bkgs);
        for (RowMap row : rows) {
            if (row.get("value") != null) {
                result.put(row.getString("brand"), BigDecimal.valueOf(row.getDouble("value")));
            }
        }
        return result;
    }

    /**
     * 获取应收账款数据（分品牌）
     */
    private Map<String, BigDecimal> getReceivableData(int year, int month, String bkgs) {
        /*StringBuilder sql = new StringBuilder("SELECT SUM(YSYE) AS receivable ")
                .append("FROM " + RECEIVABLE_DETAIL_TABLE + " ")
                .append("WHERE YEAR(RQ) = '"+year+"' AND MONTH(RQ) = '"+month+"' AND BKGS = '"+bkgs+"' ");*/
        StringBuilder sql = new StringBuilder("SELECT SUM(YSYE) AS receivable ")
                .append("FROM " + RECEIVABLE_DETAIL_TABLE + " ")
                .append("WHERE RQ = ( ")
                .append("    SELECT MAX(RQ) ")
                .append("    FROM " + RECEIVABLE_DETAIL_TABLE + " ")
                .append("    WHERE YEAR(RQ) = '" + year + "' AND MONTH(RQ) = '" + month + "' AND BKGS = '" + bkgs + "' ")
                .append(") AND BKGS = '" + bkgs + "' AND SHENGQU IN( '新疆维吾尔自治区','海南','西藏')");

        Map<String, BigDecimal> result = new HashMap<>();
        List<RowMap> rows = DBSql.getMaps(sql.toString());
        for (RowMap row : rows) {
            if (row.get("receivable") != null) {
                result.put(bkgs, BigDecimal.valueOf(row.getDouble("receivable")));
            }
        }
        return result;
    }

    private Map<String, BigDecimal> getBoneReceivable(int year, int month, String bkgs) {
        return getReceivableData(year, month, bkgs);
    }

    private Map<String, BigDecimal> getPaintReceivable(int year, int month, String bkgs) {
        return getReceivableData(year, month, bkgs);
    }

    // ==================== 数据保存方法 ====================

    /**
     * 保存汇总数据到指定表
     */
    private void saveSummaryData(BO summary, String tableName) {
        try {
            SDK.getBOAPI().createDataBO(tableName, summary, UserContext.fromUID("admin"));
            LOGGER.debug("{} 表数据保存成功: {}", tableName, summary);
        } catch (Exception e) {
            String errorMsg = String.format("%s 表数据保存失败: %s", tableName, e.getMessage());
            LOGGER.error(errorMsg, e);
            throw new RuntimeException(errorMsg, e);
        }
    }
    /**
     * 构建表唯一性条件（基于业务键）
     */
    private String buildUniqueCondition(String tableName, BO bo) {
        String bkgs = bo.getString("BKGS");
        switch (tableName) {
            case MATCHING_RATE_YEAR_TABLE:
                return "BKGS = '" + bkgs + "' AND YEARMONTH = '" + bo.getString("YEARMONTH") + "'";

            case PRODUCT_MONTHLY_TABLE:
                return "BKGS = '" + bkgs + "' AND YEARMONTH = '" + bo.getString("YEARMONTH") + "'" +
                        " AND PRODUCT_TYPE = '" + bo.getString("PRODUCT_TYPE") + "'" +
                        " AND BRAND = '" + bo.getString("BRAND") + "'";

            case RECEIVABLE_BRAND_MONTHLY_TABLE:
                return "BKGS = '" + bkgs + "' AND YEARMONTH = '" + bo.getString("YEARMONTH") + "'" +
//                        " AND PRODUCT_LINE = '" + bo.getString("PRODUCT_LINE") + "'" +
                        " AND BRAND = '" + bo.getString("BRAND") + "'";

            case RECEIVABLE_YEAR_TABLE:
                return "BKGS = '" + bkgs + "' AND YEARMONTH = '" + bo.getString("YEARMONTH") + "'";
//                        +
//                        " AND RECEIVABLE_TYPE = '" + bo.getString("RECEIVABLE_TYPE") + "'";

            case REVENUE_YEAR_TABLE:
                return "BKGS = '" + bkgs + "' AND YEARMONTH = '" + bo.getString("YEARMONTH") + "'" +
                        " AND PRODUCT_CATEGORY = '" + bo.getString("PRODUCT_CATEGORY") + "'";

            case UNIT_PRICE_DAILY_TABLE:
                // 日期字段特殊处理（精确到天）
                Date date = bo.get("DATE", Date.class);
                LOGGER.info("日期字段特殊处理（精确到天）：{}",date);
                String dateValue = new SimpleDateFormat("yyyy-MM-dd").format(date);
                return "BKGS = '" + bkgs + "' AND DATE = '" + dateValue + "'" +
                        " AND PRODUCT_TYPE = '" + bo.getString("PRODUCT_TYPE") + "'";

            default:
                LOGGER.warn("表 {} 未配置唯一性条件，直接创建新记录", tableName);
                return null;
        }
    }

    public void addSummaryData(List<BO> list, List<RowMap> rowMaps,String bkgs) {
        for (RowMap rowMap : rowMaps) {
            BO revenueBO = createBaseBO(bkgs);
            String category = rowMap.getString("LB_1");
            String province = rowMap.getString("PROVINCE");
            String revenueAmount = rowMap.getString("REVENUE_AMOUNT");
            String year_month = rowMap.getString("YEARMONTH");
            revenueBO.set("YEARMONTH",  year_month);
            if ("北新嘉宝莉".equals(bkgs)){
                if ("其他".equals(category)){
                    revenueBO.set("PRODUCT_CATEGORY", category);
                }else {
                    revenueBO.set("PRODUCT_CATEGORY", "涂料");
                }
            } else if ("石膏板".equals(category) || "轻钢龙骨".equals(category)) {
                revenueBO.set("PRODUCT_CATEGORY", category);
            }else {
                revenueBO.set("PRODUCT_CATEGORY", "其他");
            }
            revenueBO.set("REVENUE_AMOUNT", revenueAmount);
            revenueBO.set("SHENGQU", province);//省区
            list.add(revenueBO);
        }
    }
}