package com.awspaas.user.apps.donenow_ivt.event;

import com.actionsoft.bpms.bo.engine.BO;
import com.actionsoft.bpms.bpmn.engine.core.delegate.ProcessExecutionContext;
import com.actionsoft.bpms.bpmn.engine.listener.ExecuteListener;
import com.actionsoft.bpms.bpmn.engine.model.run.delegate.ProcessInstance;
import com.actionsoft.bpms.commons.database.RowMap;
import com.actionsoft.bpms.server.UserContext;
import com.actionsoft.bpms.util.DBSql;
import com.actionsoft.bpms.util.TypeUtil;
import com.actionsoft.sdk.local.SDK;
import com.actionsoft.sdk.local.api.Logger;
import com.awspaas.user.apps.donenow_ivt.constant.IVTConstant;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

public class ivtOrderProcessAfterComplete extends ExecuteListener {
    public String getDescription() {
        return "流程结束事件：采购订单审批完成后触发";
    }

    private static final Logger logger = SDK.getLogAPI().getLogger(ivtOrderProcessAfterComplete.class);//记录日志
    private final String[] excludesArray = new String[]{"ID", "ORGID", "BINDID", "CREATEDATE", "CREATEUSER", "UPDATEDATE", "UPDATEUSER"};

    /**
     * 采购订单审批完成后触发
     * @param processExecutionContext
     * @throws Exception
     */
    @Override
    public void execute(ProcessExecutionContext processExecutionContext) throws Exception {
        String BINDID = processExecutionContext.getProcessInstance().getId();
        UserContext uc = processExecutionContext.getUserContext();

        BO purchaseOrder = SDK.getBOAPI().getByProcess("BO_EU_DNIVT_ORDER", BINDID);
        purchaseOrder.set("STATUS_ID", "2152");//采购中
        SDK.getBOAPI().update("BO_EU_DNIVT_ORDER", purchaseOrder);

        String orderId = purchaseOrder.getId(); // 获取订单ID
        System.out.println("采购订单审批完成，开始自动生成付款计划，订单ID：" + orderId);

        List<BO> orderProducts = SDK.getBOAPI().query("BO_EU_DNIVT_ORDER_PRODUCT").bindId(BINDID).list();
        for (BO orderProduct : orderProducts) {

            orderProduct.set("ORDER_ID", purchaseOrder.getId());
            SDK.getBOAPI().update("BO_EU_DNIVT_ORDER_PRODUCT", orderProduct);

            if (StringUtils.isNotBlank(orderProduct.getString("CONTRACT_COST_ID"))) {
                BO cost = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_COST", orderProduct.getString("CONTRACT_COST_ID"));

                cost.set("STATUS_ID", "1235");//更新状态 采购中
                SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_COST", cost);

                //排除重复提交
                /*
                String sql = "SELECT ID FROM BO_EU_DNCTT_CONTRACT_COST_PRODUCT WHERE ORDER_ID=? AND CONTRACT_COST_ID=?";
                String id = DBSql.getString(sql, new Object[]{purchaseOrder.getId(), cost.getId()});
                SDK.getBOAPI().remove("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", id);//删除旧数据
                 */

                String costProductID = DBSql.getString("SELECT ID FROM BO_EU_DNCTT_CONTRACT_COST_PRODUCT WHERE ORDER_ID=? AND CONTRACT_COST_ID=?", new Object[]{purchaseOrder.getId(), cost.getId()});
                if (StringUtils.isBlank(costProductID)) {
                    ProcessInstance processInstance = SDK.getProcessAPI().createBOProcessInstance("obj_6bc913271069455abbd516c556b26d31", processExecutionContext.getUserContext().getUID(), "合同产品物流管理");

                    //提交采购订单添加成本产品
                    BO costProduct = new BO();
                    costProduct.setBindId(processInstance.getId());
                    costProduct.set("ORDER_ID", purchaseOrder.getId());
                    costProduct.set("CONTRACT_COST_ID", cost.getString("ID"));
                    costProduct.set("STATUS_ID", "2156");//采购中
                    costProduct.set("QUANTITY", orderProduct.get("QUANTITY"));
                    costProduct.set("WAREHOUSE_ID", orderProduct.get("WAREHOUSE_ID"));
                    costProduct.set("SN", DBSql.getString("SELECT GROUP_CONCAT(SN) FROM BO_EU_DNIVT_WAREHOUSE_PRODUCT_LOT WHERE ORDER_PRODUCT_ID=?", new Object[]{orderProduct.getId()}));
                    costProduct.set("OLD_QUANTITY", costProduct.get("QUANTITY"));//配送数量

                    costProduct.set("SHIPPING_TYPE_ID", null);
                    dn.recordFormChanges.record(uc, costProduct, "采购产品审批后新增");
                    SDK.getBOAPI().create("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", costProduct, processInstance, uc);
                } else {
                    BO costProduct = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", costProductID);
                    costProduct.set("ORDER_ID", purchaseOrder.getId());
                    costProduct.set("CONTRACT_COST_ID", cost.getString("ID"));
                    costProduct.set("STATUS_ID", "2156");//采购中
                    costProduct.set("QUANTITY", orderProduct.get("QUANTITY"));
                    costProduct.set("WAREHOUSE_ID", orderProduct.get("WAREHOUSE_ID"));
                    costProduct.set("SN", DBSql.getString("SELECT GROUP_CONCAT(SN) FROM BO_EU_DNIVT_WAREHOUSE_PRODUCT_LOT WHERE ORDER_PRODUCT_ID=?", new Object[]{orderProduct.getId()}));
                    costProduct.set("OLD_QUANTITY", costProduct.get("QUANTITY"));//配送数量
                    costProduct.set("SHIPPING_TYPE_ID", null);
                    dn.recordFormChanges.record(uc, costProduct, "采购产品审批后新增");
                    SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", costProduct);
                }

                //已完成拣货或者在采购中

                //仍需数量：
                String needsql = "SELECT a.QUANTITY-SUM(ifnull(b.QUANTITY,0)) FROM BO_EU_DNCTT_CONTRACT_COST a LEFT JOIN BO_EU_DNCTT_CONTRACT_COST_PRODUCT b ON a.ID=b.CONTRACT_COST_ID AND b.CLOSED = 0 WHERE a.ID=?";
                if (DBSql.getInt(needsql, new Object[]{cost.getId()}) <= 0) {
                    //更新状态
                    cost.set("STATUS_ID", 1235); //1235 采购中
                    SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_COST", cost);
                }

                //更新采购订单号
                String PURCHASE_ORDER_NO = DBSql.getString("SELECT GROUP_CONCAT(PURCHASE_ORDER_NO) FROM " + IVTConstant.BO_EU_DNIVT_ORDER + " WHERE CLOSED=0 AND ISEND=1 AND ID IN (SELECT ORDER_ID FROM BO_EU_DNIVT_ORDER_PRODUCT WHERE CONTRACT_COST_ID=?) ", new Object[]{cost.getString("ID")});
                DBSql.update("UPDATE BO_EU_DNCTT_CONTRACT_COST SET PURCHASE_ORDER_NO=? WHERE ID=?", new Object[]{PURCHASE_ORDER_NO, cost.getString("ID")});

            }

        }

        //生成付款计划-- 胡磊 旧版
        //createPaymentPlan(uc,orderId);

/*****************************************2025年10月24日  张耀 生成付款计划********************************************/
        logger.info("生成付款计划");
        int total = 0;
        for (BO orderProduct : orderProducts) {
            if (StringUtils.isNotBlank(orderProduct.getString("CONTRACT_COST_ID"))) {
                String SERVICE_ID = DBSql.getString("select SERVICE_ID from BO_EU_DNCTT_CONTRACT_COST where ID=?", new Object[]{orderProduct.getString("CONTRACT_COST_ID")});
                if (StringUtils.isNotBlank(SERVICE_ID)) {

                    if (DBSql.getInt("select count(1) as cnt from  BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=?  AND PAY_AMOUNT is NOT null AND PAY_AMOUNT<>0", new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID}) > 0) {
                        continue;
                    }
                    String sql = "delete from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=? and (PAY_AMOUNT is null or PAY_AMOUNT = 0)";
                    DBSql.update(sql, new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID});

                    logger.info("生成付款计划SERVICE_ID--" + SERVICE_ID);

                    BO service = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", SERVICE_ID);
                    String BILL_METHOD_ID = null;//计费方式  4601:自然月  4602:实际月
                    if (service.getString("OBJECT_TYPE").equals("2"))//服务包
                    {
                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE_BUNDLE where ID=?", new Object[]{service.getString("OBJECT_ID")});
                    } else {
                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE where ID=?", new Object[]{service.getString("OBJECT_ID")});
                    }

                    String RULE_CATE = service.getString("PURCHASE_PERIOD_TYPE");//采购周期
                    LocalDate PERIOD_BEGIN_DATE = service.get("EFFECTIVE_DATE", LocalDate.class);

                    LocalDate START_DATE = TypeUtil.convert(DBSql.getString("select START_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);

                    LocalDate PERIOD_END_DATE = TypeUtil.convert(DBSql.getString("select END_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);

                    List<PERIOD> periods = getPeriodList(RULE_CATE, PERIOD_BEGIN_DATE, START_DATE, PERIOD_END_DATE, StringUtils.isNotBlank(BILL_METHOD_ID) && BILL_METHOD_ID.equals("4601"));

                    if (periods.isEmpty())
                        continue;

                    BigDecimal COST_TOTAL = orderProduct.get("COST_TOTAL", BigDecimal.class);//总金额

                    BigDecimal RATE_TOTAL = periods.stream().map(period -> period.getRate()).reduce(BigDecimal.ZERO, BigDecimal::add);

                    if (RATE_TOTAL.equals(BigDecimal.ZERO) || COST_TOTAL == null || COST_TOTAL.equals(BigDecimal.ZERO))
                        continue;

                    BigDecimal UNIT_COST = COST_TOTAL.divide(RATE_TOTAL, 10, RoundingMode.HALF_UP);
                    for (PERIOD period : periods) {
                        total++;
                        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");

                        BO paymentPlan = new BO();
                        paymentPlan.setBindId(processInstance.getId());
                        paymentPlan.set("ORDER_ID", orderId);
                        paymentPlan.set("PLAN_DATE", period.getPeriodBeginDateStr());
                        paymentPlan.set("PLAN_AMOUNT", UNIT_COST.multiply(period.getRate()));
                        paymentPlan.set("REMAIN_AMOUNT", paymentPlan.get("PLAN_AMOUNT"));
                        paymentPlan.set("CONTRACT_COST_ID", orderProduct.getString("CONTRACT_COST_ID"));
                        paymentPlan.set("CONTRACT_SERVICE_ID", service.getId());
                        SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc);

                        System.out.println("==== 创建付款计划：" + paymentPlan.get("PLAN_DATE") + "，金额：" + paymentPlan.get("PLAN_AMOUNT") + " ====");
                    }
                }
            }
        }
        logger.info("付款计划生成完成，生成付款计划数量：" + total);
    }

    /**
     * 生成采购计划
     * @param uc
     * @param orderId
     */
    private void createPaymentPlan(UserContext uc, String orderId) {

        System.out.println("==== 开始执行自动生成付款计划逻辑 ====");
        try {

            List<Map<String, Object>> servicePlanData = queryPaymentPlan(uc, orderId);
            boolean isServiceOrder = !servicePlanData.isEmpty();
            System.out.println("==== 订单类型判断：" + (isServiceOrder ? "服务类" : "非服务类") + "，服务类计划数量：" + servicePlanData.size() + " ====");

            List<Map<String, Object>> payAmounts = queryPayAmount(uc, orderId);
            boolean hasValidPayment = payAmounts.stream().anyMatch(amountMap -> {
                Double amount = (Double) amountMap.get("实际付款金额");
                return amount != null && amount > 0;
            });
            System.out.println("==== 有效付款检查结果：" + (hasValidPayment ? "存在有效付款" : "无有效付款") + " ====");

            if (hasValidPayment) {
                System.out.println("==== 因存在有效付款，终止付款计划生成 ====");
                return;
            }

            int deletedCount = deleteUnpaidPaymentPlan(uc, orderId);
            System.out.println("==== 已删除旧未付款计划数量：" + deletedCount + " ====");

            if (isServiceOrder) {
                int createCount = 0;
                for (Map<String, Object> plan : servicePlanData) {
                    String planDate = (String) plan.get("计划付款时间");
                    Double planAmount = (Double) plan.get("计划付款金额");
                    if (StringUtils.isNotBlank(planDate) && planAmount != null && planAmount > 0) {
                        createPaymentPlan(uc, orderId, planDate, planAmount);
                        createCount++;
                    }
                }
                System.out.println("==== 服务类付款计划创建完成，成功创建：" + createCount + "条 ====");
            } else {
                Map<String, Object> dateInfo = queryNonServiceOrderDate(uc, orderId);
                Map<String, Object> priceInfo = queryNonServiceOrderPrice(uc, orderId);
                System.out.println("==== 非服务类订单 - 日期信息：" + (dateInfo != null ? dateInfo : "无数据") + "，价格信息：" + (priceInfo != null ? priceInfo : "无数据") + " ====");

                if (dateInfo != null && priceInfo != null) {
                    String planDate = (String) dateInfo.get("EXPECTED_SHIP_DATE");
                    Double planAmount = (Double) priceInfo.get("cost_total");

                    if (StringUtils.isNotBlank(planDate)) {
                        createPaymentPlan(uc, orderId, planDate, planAmount);
                        System.out.println("==== 非服务类付款计划创建完成，日期：" + planDate + "，金额：" + planAmount + " ====");
                    } else {
                        throw new Exception("非服务类订单数据不完整：日期=" + planDate + "，金额=" + planAmount);
                    }
                } else {
                    throw new Exception("未查询到非服务类订单的日期或价格信息");
                }
            }

            System.out.println("==== 订单【" + orderId + "】付款计划自动生成流程全部完成 ====");
        } catch (Exception e) {
            System.err.println("==== 自动生成付款计划失败：" + e.getMessage() + " ====");
            e.printStackTrace();
        }

    }

    private List<Map<String, Object>> queryPaymentPlan(UserContext uc, String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return Collections.emptyList();
        }

        String mainSql = "SELECT " + "a.order_id 采购订单id, " + "a.CONTRACT_SERVICE_ID 合同服务ID, " + "b.PERIOD_END_DATE 计划付款时间, " + "b.PERIOD_COST 计划付款金额 " + "FROM `BO_EU_DNIVT_ORDER_PRODUCT` a " + "JOIN `BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD` b " + "ON a.CONTRACT_SERVICE_ID = b.CONTRACT_SERVICE_ID " + "WHERE a.ORDER_ID = ?";
        List<RowMap> mainRowMaps = DBSql.getMaps(mainSql, new Object[]{orderId});

        List<Map<String, Object>> resultList = new ArrayList<>();
        Set<String> processedServiceIds = new HashSet<>();

        if (mainRowMaps != null && !mainRowMaps.isEmpty()) {
            for (RowMap mainRow : mainRowMaps) {
                Map<String, Object> plan = new HashMap<>();
                plan.put("order_id", mainRow.getString("采购订单id"));
                plan.put("计划付款时间", mainRow.getString("计划付款时间"));
                plan.put("计划付款金额", mainRow.getDouble("计划付款金额"));
                resultList.add(plan);

                String contractServiceId = mainRow.getString("合同服务ID");
                if (StringUtils.isNotBlank(contractServiceId) && !processedServiceIds.contains(contractServiceId)) {
                    processedServiceIds.add(contractServiceId);

                    String adjustSql = "SELECT " + "effective_date 计划付款时间, " + "prorated_cost_change 计划付款金额 " + "FROM `BO_EU_DNCTT_CONTRACT_SERVICE_ADJUST` " + "WHERE CAST(CONTRACT_SERVICE_ID AS CHAR) = ?";
                    List<RowMap> adjustRowMaps = DBSql.getMaps(adjustSql, new Object[]{contractServiceId});

                    if (adjustRowMaps != null && !adjustRowMaps.isEmpty()) {
                        for (RowMap adjustRow : adjustRowMaps) {
                            Map<String, Object> adjustPlan = new HashMap<>();
                            adjustPlan.put("order_id", orderId);
                            adjustPlan.put("计划付款时间", adjustRow.getString("计划付款时间"));
                            adjustPlan.put("计划付款金额", adjustRow.getDouble("计划付款金额"));
                            resultList.add(adjustPlan);
                        }
                    }
                }
            }
        }
        return resultList;
    }

    private List<Map<String, Object>> queryPayAmount(UserContext uc, String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return Collections.emptyList();
        }

        String sql = "select " + "ORDER_ID 采购订单id, " + "PAY_AMOUNT 实际付款金额 " + "from `BO_EU_DNIVT_ORDER_PAYMENT_PLAN` " + "where ORDER_ID = ?";
        List<RowMap> rowMaps = DBSql.getMaps(sql, new Object[]{orderId});

        List<Map<String, Object>> resultList = new ArrayList<>();
        if (rowMaps != null && !rowMaps.isEmpty()) {
            for (RowMap row : rowMaps) {
                Map<String, Object> amountInfo = new HashMap<>();
                amountInfo.put("order_id", orderId);
                amountInfo.put("实际付款金额", row.getDouble("实际付款金额"));
                resultList.add(amountInfo);
            }
        }
        return resultList;
    }


    private int deleteUnpaidPaymentPlan(UserContext uc, String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return 0;
        }

        String sql = "delete from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and (PAY_AMOUNT is null or PAY_AMOUNT = 0)";
        return DBSql.update(sql, new Object[]{orderId});
    }


    private void createPaymentPlan(UserContext uc, String orderId, String planDate, Double planAmount) throws Exception {
        // 1. 原有参数校验（保持不变）
        if (StringUtils.isBlank(orderId) || StringUtils.isBlank(planDate) || planAmount == null) {
            throw new Exception("创建付款计划参数不完整：orderId=" + orderId + "，planDate=" + planDate + "，planAmount=" + planAmount);
        }

        // 2. 新增：通过orderId查询订单表，获取VENDOR_ACCOUNT_ID（遵循当前类SQL风格）
        String queryVendorSql = "select VENDOR_ACCOUNT_ID from BO_EU_DNIVT_ORDER where id = ?";
        String vendorAccountId = DBSql.getString(queryVendorSql, new Object[]{orderId});
        // 处理查询结果（空值/无数据时抛异常，与现有异常风格一致）
        if (StringUtils.isBlank(vendorAccountId)) {
            throw new Exception("创建付款计划失败：订单不存在或VENDOR_ACCOUNT_ID为空，orderId=" + orderId);
        }
        System.out.println("==== 查询订单表成功，VENDOR_ACCOUNT_ID=" + vendorAccountId + " ====");

        // 3. 原有流程实例创建（保持不变）
        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
        System.out.println("==== 付款计划流程实例创建成功，bindId=" + processInstance.getId() + " ====");

        // 4. 构建BO对象（新增：设置ACCOUNT_PAYEE=查询到的VENDOR_ACCOUNT_ID）
        BO bo = new BO();
        bo.setBindId(processInstance.getId());
        bo.set("ORDER_ID", orderId);
        bo.set("PLAN_DATE", planDate);
        bo.set("PLAN_AMOUNT", planAmount);
        bo.set("ACCOUNT_PAYEE", vendorAccountId); // 关键新增：赋值ACCOUNT_PAYEE
        System.out.println("==== BO对象构建完成，ACCOUNT_PAYEE=" + vendorAccountId + " ====");

        // 5. 原有业务数据创建（保持不变）
        SDK.getBOAPI().createDataBO("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", bo, uc);
        System.out.println("==== 付款计划数据创建成功，orderId=" + orderId + " ====");
    }


    private Map<String, Object> queryNonServiceOrderDate(UserContext uc, String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return null;
        }

        String sql = "select EXPECTED_SHIP_DATE " + "from `BO_EU_DNIVT_ORDER` " + "where id = ? ";
        String expectedShipDate = DBSql.getString(sql, new Object[]{orderId});

        if (StringUtils.isBlank(expectedShipDate)) {
            return null;
        }

        Map<String, Object> dateInfo = new HashMap<>();
        dateInfo.put("order_id", orderId);
        dateInfo.put("EXPECTED_SHIP_DATE", expectedShipDate);
        return dateInfo;
    }


    private Map<String, Object> queryNonServiceOrderPrice(UserContext uc, String orderId) {
        // 入参校验：订单ID为空返回null（与日期方法风格一致）
        if (StringUtils.isBlank(orderId)) {
            return null;
        }

        // SQL查询：求和 cost_total 字段（数据库字段正确，无需修改）
        String sql = "select sum(`cost_total`) " + "from `BO_EU_DNIVT_ORDER_PRODUCT` " + "where order_id = ? ";
        String totalCostStr = DBSql.getString(sql, new Object[]{orderId});

        // 空值处理：查询结果为空返回null（与日期方法风格一致）
        if (StringUtils.isBlank(totalCostStr)) {
            return null;
        }

        // 数值转换：字符串转Double（异常时返回null）
        Double totalCost;
        try {
            totalCost = Double.parseDouble(totalCostStr);
        } catch (NumberFormatException e) {
            return null;
        }

        // 结果封装：返回字段名改为 cost_total（小写+下划线，与前端完全对齐）
        Map<String, Object> priceInfo = new HashMap<>();
        priceInfo.put("order_id", orderId);
        priceInfo.put("cost_total", totalCost); // 关键修改：字段名从 TOTAL_COST 改为 cost_total
        return priceInfo;
    }


    /*************************************2025年10月23日**************************************************/

    /**
     * 获取周期列表
     * @param RULE_CATE
     * @param CONTRACT_START_DATE
     * @param PERIOD_BEGIN_DATE
     * @param PERIOD_END_DATE
     * @param isNaturalMonth //自然月和实际月
     * @return
     */
    private List<PERIOD> getPeriodList(String RULE_CATE, LocalDate CONTRACT_START_DATE, LocalDate PERIOD_BEGIN_DATE, LocalDate PERIOD_END_DATE, boolean isNaturalMonth) {

        logger.info("获取周期列表");
        logger.info("RULE_CATE:" + RULE_CATE);
        logger.info("CONTRACT_START_DATE:" + CONTRACT_START_DATE);
        logger.info("PERIOD_BEGIN_DATE:" + PERIOD_BEGIN_DATE);
        logger.info("PERIOD_END_DATE:" + PERIOD_END_DATE);
        logger.info("isNaturalMonth:" + isNaturalMonth);

        List<PERIOD> periodList = new ArrayList<>();
        //一次性收费
        if (RULE_CATE.equals(IVTConstant.PERIOD_TYPE_ONE_TIME)) {
            PERIOD period = new PERIOD();
            period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
            period.setPeriodEndDate(PERIOD_END_DATE);
            period.setRate(BigDecimal.ONE);
            periodList.add(period);
        } else {
            LocalDate START_DATE = null;
            LocalDate currLastDay = null;//当前周期的结束日
            int periodDays = 0;//当前周期天数
            switch (RULE_CATE) {
                case IVTConstant.PERIOD_TYPE_MONTH://按月支付
                {
                    if (isNaturalMonth) {
                        //自然月
                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1) {
                            currLastDay = PERIOD_BEGIN_DATE.with(TemporalAdjusters.lastDayOfMonth());
                            periodDays = PERIOD_BEGIN_DATE.lengthOfMonth();
                        }
                    } else {
                        //实际月
                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
                        {
                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(1), currLastDay);

                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
                            currLastDay = CONTRACT_START_DATE.plusMonths(1).minusDays(1);

                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);

                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
                            {
                                currLastDay = PERIOD_END_DATE;
                            }

                        } else {


                        }
                    }
                }
                break;
                case IVTConstant.PERIOD_TYPE_QUARTER://按季支付
                {
                    if (isNaturalMonth) {
                        //如果不是季度第一天
                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 3 != 0) {
                            Month endMonth = getQuarterEndMonth(PERIOD_BEGIN_DATE.getMonth());
                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()) // 考虑闰年2月的天数
                            );
                            periodDays = getDaysInCurrentQuarter(PERIOD_BEGIN_DATE);
                        }
                    } else {
                        //实际月
                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
                        {
                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(3), currLastDay);

                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
                            currLastDay = CONTRACT_START_DATE.plusMonths(3).minusDays(1);

                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);

                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
                            {
                                currLastDay = PERIOD_END_DATE;
                            }

                        } else {


                        }
                    }

                }
                break;
                case IVTConstant.PERIOD_TYPE_HALFYEAR://按半年支付
                    if (isNaturalMonth) {
                        // 若不是半年第一天，计算本半年剩余天数作为首个周期
                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 6 != 0) {
                            Month endMonth = getHalfYearEndMonth(PERIOD_BEGIN_DATE.getMonth());
                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()));
                            periodDays = getDaysInCurrentHalfYear(PERIOD_BEGIN_DATE);
                        }
                    } else {
                        //实际月
                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
                        {
                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(6), currLastDay);

                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
                            currLastDay = CONTRACT_START_DATE.plusMonths(6).minusDays(1);

                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);

                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
                            {
                                currLastDay = PERIOD_END_DATE;
                            }

                        } else {


                        }
                    }
                    break;
                case IVTConstant.PERIOD_TYPE_YEAR://按年支付
                {
                    if (isNaturalMonth) {
                        //如果不是年第一天
                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || PERIOD_BEGIN_DATE.getMonthValue() != 1) {
                            //所在年最后一天
                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), 12, 31);
                            periodDays = PERIOD_BEGIN_DATE.lengthOfYear();
                        }

                    } else {
                        //实际月
                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
                        {
                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(12), currLastDay);

                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
                            currLastDay = CONTRACT_START_DATE.plusMonths(12).minusDays(1);

                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);

                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
                            {
                                currLastDay = PERIOD_END_DATE;
                            }
                        } else {


                        }
                    }
                }
                break;
                default: {
                    //报错，类型异常
                    return null;
                }
            }
            logger.info("currLastDay:" + currLastDay);
            logger.info("periodDays:" + periodDays);

            if (currLastDay != null) {
                if (currLastDay.isBefore(PERIOD_END_DATE)) {
                    PERIOD period = new PERIOD();
                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
                    period.setPeriodEndDate(currLastDay);

                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, currLastDay), periodDays);
                    period.setRate(periodRate);

                    periodList.add(period);

                    START_DATE = currLastDay.plusDays(1);//周期开始日期
                } else {
                    PERIOD period = new PERIOD();
                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
                    period.setPeriodEndDate(PERIOD_END_DATE);

                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, PERIOD_END_DATE), periodDays);
                    period.setRate(periodRate);

                    periodList.add(period);
                }
            } else {
                START_DATE = PERIOD_BEGIN_DATE;
            }

            logger.info("START_DATE:" + START_DATE);

            //循环
            if (START_DATE != null && START_DATE.isBefore(PERIOD_END_DATE)) {

                while (!START_DATE.isAfter(PERIOD_END_DATE)) {
                    LocalDate periodEnd = getNextPeriodStart(START_DATE, RULE_CATE).minusDays(1);//本周期结束时间

                    BigDecimal periodRate = BigDecimal.ONE;

                    if (periodEnd.isAfter(PERIOD_END_DATE)) {//如果结束日期大于合同结束日期，则计算结束日期和合同结束日期的差值，并计算该差值占整周期的比例
                        periodRate = divideToBigDecimal(GetPeriodDays(START_DATE, PERIOD_END_DATE), GetPeriodDays(START_DATE, periodEnd));
                        periodEnd = PERIOD_END_DATE;
                    }

                    PERIOD period = new PERIOD();
                    period.setPeriodBeginDate(START_DATE);
                    period.setPeriodEndDate(periodEnd);
                    period.setRate(periodRate);
                    periodList.add(period);

                    if (periodEnd != null) {
                        START_DATE = periodEnd.plusDays(1);
                    }
                }
            }
        }
        return periodList;
    }

    /**
     * 获取下一周期开始时间
     * @param start 当前周期开始时间
     * @param periodType 周期类型
     * @return 下一周期开始时间
     */
    public static LocalDate getNextPeriodStart(LocalDate start, String periodType) {
        // 根据不同的周期类型计算下一周期的开始时间
        switch (periodType) {
            case IVTConstant.PERIOD_TYPE_MONTH:
                // 如果是月周期，则在当前时间基础上增加1个月
                return start.plus(1, ChronoUnit.MONTHS);
            case IVTConstant.PERIOD_TYPE_QUARTER:
                // 如果是季度周期，则在当前时间基础上增加3个月
                return start.plus(3, ChronoUnit.MONTHS);
            case IVTConstant.PERIOD_TYPE_HALFYEAR:
                // 如果是半年周期，则在当前时间基础上增加6个月
                return start.plus(6, ChronoUnit.MONTHS);
            case IVTConstant.PERIOD_TYPE_YEAR:
                // 如果是年周期，则在当前时间基础上增加1年
                return start.plus(1, ChronoUnit.YEARS);
            default:
                // 如果周期类型不匹配任何已知类型，则返回原始开始时间
                return start;
        }
    }

    /**
     * 获取当前季度的结束月份
     */
    private static Month getQuarterEndMonth(Month month) {
        int monthValue = month.getValue();
        if (monthValue <= 3) {
            return Month.MARCH;   // 第一季度结束月
        } else if (monthValue <= 6) {
            return Month.JUNE;    // 第二季度结束月
        } else if (monthValue <= 9) {
            return Month.SEPTEMBER; // 第三季度结束月
        } else {
            return Month.DECEMBER;  // 第四季度结束月
        }
    }

    /**
     * 计算当前季度的总天数
     */
    private static int getDaysInCurrentQuarter(LocalDate date) {
        // 获取当前月份
        Month currentMonth = date.getMonth();
        // 确定当前季度的起始月份和结束月份
        Month startMonth = getQuarterStartMonth(currentMonth);
        Month endMonth = getQuarterEndMonth(currentMonth);

        // 构建季度的第一天（当月第一天）
        LocalDate quarterStart = LocalDate.of(date.getYear(), startMonth, 1);

        // 构建季度的最后一天（当月最后一天）
        LocalDate quarterEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()) // 考虑闰年2月的天数
        );

        // 计算两个日期之间的天数（包含首尾两天）
        return (int) ChronoUnit.DAYS.between(quarterStart, quarterEnd) + 1;
    }

    /**
     * 获取当前季度的起始月份
     */
    private static Month getQuarterStartMonth(Month month) {
        int monthValue = month.getValue();
        if (monthValue <= 3) {
            return Month.JANUARY; // 第一季度：1-3月
        } else if (monthValue <= 6) {
            return Month.APRIL;   // 第二季度：4-6月
        } else if (monthValue <= 9) {
            return Month.JULY;    // 第三季度：7-9月
        } else {
            return Month.OCTOBER; // 第四季度：10-12月
        }
    }

    /**
     * 获取当前半年的结束月份
     */
    private static Month getHalfYearEndMonth(Month month) {
        int monthValue = month.getValue();
        return monthValue <= 6 ? Month.JUNE : Month.DECEMBER;
    }

    /**
     * 获取当前半年的起始月份
     */
    private static Month getHalfYearStartMonth(Month month) {
        int monthValue = month.getValue();
        return monthValue <= 6 ? Month.JANUARY : Month.JULY;
    }

    /**
     * 计算当前半年的总天数
     */
    private static int getDaysInCurrentHalfYear(LocalDate date) {
        Month currentMonth = date.getMonth();
        Month startMonth = getHalfYearStartMonth(currentMonth);
        Month endMonth = getHalfYearEndMonth(currentMonth);

        LocalDate halfYearStart = LocalDate.of(date.getYear(), startMonth, 1);
        LocalDate halfYearEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()));

        return GetPeriodDays(halfYearStart, halfYearEnd);
    }

    private static int GetPeriodDays(LocalDate start, LocalDate end) {
        return (int) ChronoUnit.DAYS.between(start, end) + 1;
    }

    // 定义一个方法，将两个 int 相除并返回 BigDecimal
    public static BigDecimal divideToBigDecimal(int numerator, int denominator) {
        if (denominator == 0) {
            throw new ArithmeticException("分母不能为零");
        }

        // 使用 BigDecimal 进行精确计算
        BigDecimal num = new BigDecimal(numerator);
        BigDecimal den = new BigDecimal(denominator);

        // 设置小数点后的位数和舍入模式
        return num.divide(den, 10, RoundingMode.HALF_UP); // 保留 10 位小数
    }

    /**
     * 周期
     */
    private class PERIOD {
        private LocalDate PERIOD_BEGIN_DATE;
        private LocalDate PERIOD_END_DATE;
        private BigDecimal RATE;

        public void setPeriodBeginDate(LocalDate periodBeginDate) {
            this.PERIOD_BEGIN_DATE = periodBeginDate;
        }

        public void setPeriodEndDate(LocalDate periodEndDate) {
            this.PERIOD_END_DATE = periodEndDate;
        }

        public void setRate(BigDecimal rate) {
            this.RATE = rate;
        }

        public LocalDate getPeriodBeginDate() {
            return PERIOD_BEGIN_DATE;
        }

        public LocalDate getPeriodEndDate() {
            return PERIOD_END_DATE;
        }

        public String getPeriodBeginDateStr() {
            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }

        public String getPeriodMonthStr() {
            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyyMM"));
        }

        public String getPeriodEndDateStr() {
            return PERIOD_END_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }

        public BigDecimal getRate() {
            return RATE;
        }

    }


}
