# HotelKpiM3MonthlyReportTotalsParseService.java

    package cloud.wconnect.workperformance.service.hotelkpi.m3;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.exception.InternalServerErrorException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.workperformance.pojo.bo.hotelkpi.m3.HotelKpiM3MonthlyReportTotalsBO;
    import cloud.wconnect.workperformance.pojo.bo.hotelkpi.m3.HotelKpiM3MonthlyReportTotalsValueBO;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;

    import java.io.InputStream;
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * 解析报告：M3 Monthly Report Totals
     *
     * @author zc
     * @date 2025/08/27
     */
    @Slf4j
    @Component
    @DS("work_performance")
    public class HotelKpiM3MonthlyReportTotalsParseService {

        private static final MonthlyReportTotalsFullParser monthlyReportTotalsFullParser = new MonthlyReportTotalsFullParser();

        /**
         * 解析报告：M3 Monthly Report Totals
         *
         * @param propertyDTOList 资产列表
         * @param in              文件
         * @return 解析结果
         * @throws ParseReportException 解析异常
         * @author zc
         * @date 2025/8/27
         */
        public List<HotelKpiM3MonthlyReportTotalsBO> parse(List<PropertyDTO> propertyDTOList, InputStream in) throws ParseReportException {
            try {
                String monthlyResult = monthlyReportTotalsFullParser.parse(in);

                // 解析JSON并排序
                ObjectMapper mapper = new ObjectMapper();
                mapper.enable(SerializationFeature.INDENT_OUTPUT);

                List<MonthlyReportTotalsFullParser.PropertyGroup> propertyGroups =
                        mapper.readValue(monthlyResult, new TypeReference<>() {
                        });

                List<HotelKpiM3MonthlyReportTotalsBO> result = Lists.newArrayList();

                // 将 propertyGroups 按 property 分组
                Map<String, List<MonthlyReportTotalsFullParser.PropertyGroup>> propertyGroupsByProperty =
                        propertyGroups.stream().collect(Collectors.groupingBy(pg -> pg.property));

                // 遍历每个资产，查找匹配的 propertyGroup
                for (PropertyDTO propertyDTO : propertyDTOList) {
                    RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(propertyDTO
                            .getInternationalization().getNumber().getCalculationRule());

                    HotelKpiM3MonthlyReportTotalsBO bo = new HotelKpiM3MonthlyReportTotalsBO();
                    bo.setPropertyId(propertyDTO.getId());
                    List<MonthlyReportTotalsFullParser.PropertyGroup> matchedGroups =
                            M3ReportCommonUtils.getIgnoreCase(propertyGroupsByProperty, propertyDTO.getName());
                    if (matchedGroups == null || matchedGroups.isEmpty()) {
                        continue;
                    }
                    matchedGroups.forEach(pg -> setPropertyGroupToBO(pg, bo, roundingMode));
                    result.add(bo);
                }
                return result;
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Handle parse Hotel KPI M3 Monthly Report Totals report error.", e);
            }
        }

        /**
         * 将 PropertyGroup 数值设置到 HotelKpiM3MonthlyReportTotalsBO
         *
         * @param propertyGroup PropertyGroup 对象
         * @param bo            对象
         * @param roundingMode  舍入模式
         * @author zc
         * @date 2025/8/27
         */
        private void setPropertyGroupToBO(MonthlyReportTotalsFullParser.PropertyGroup propertyGroup,
                                          HotelKpiM3MonthlyReportTotalsBO bo, RoundingMode roundingMode) {
            // 计算该 PropertyGroup 下所有 items 的总和
            HotelKpiM3MonthlyReportTotalsValueBO valueBO = calculateCategoryTotal(propertyGroup.items, roundingMode);

            String category = propertyGroup.category.toLowerCase();
            if (category.contains("food") && category.contains("beverage")) {
                // F&B Revenue 对应 Food & Beverage Revenue 分类
                bo.setFbRevenue(valueBO);
            } else if (category.contains("banquet")) {
                // Banquet Revenue 对应 Banquet Revenue 分类
                bo.setBanquetRevenue(valueBO);
            } else if (category.contains("other")) {
                // Other Revenue 对应 Other Revenue 分类
                bo.setOtherRevenue(valueBO);
            }
        }

        /**
         * 计算分类总和
         *
         * @param items        分类下的所有项目
         * @param roundingMode 舍入模式
         * @return HotelKpiM3MonthlyReportTotalsValueBO 对象
         * @author zc
         * @date 2025/8/27
         */
        private HotelKpiM3MonthlyReportTotalsValueBO calculateCategoryTotal(List<MonthlyReportTotalsFullParser.ReportItem> items,
                                                                            RoundingMode roundingMode) {
            BigDecimal currentTotal = BigDecimal.ZERO;
            BigDecimal budgetTotal = BigDecimal.ZERO;
            BigDecimal previousTotal = BigDecimal.ZERO;

            for (MonthlyReportTotalsFullParser.ReportItem item : items) {
                if (item == null) {
                    continue;
                }
                // 跳过 "Total"
                if (item.name.equalsIgnoreCase("total")) {
                    continue;
                }
                currentTotal = currentTotal.add(M3ReportCommonUtils.parseCurrencyValue(item.month_total));
                budgetTotal = budgetTotal.add(M3ReportCommonUtils.parseCurrencyValue(item.mtd_budget));
                previousTotal = previousTotal.add(M3ReportCommonUtils.parseCurrencyValue(item.month_total_ly));
            }

            HotelKpiM3MonthlyReportTotalsValueBO valueBO = new HotelKpiM3MonthlyReportTotalsValueBO();
            valueBO.setMonthTotal(currentTotal.setScale(BaseConstant.DATA_PRECISION, roundingMode));
            valueBO.setMtdBudget(budgetTotal.setScale(BaseConstant.DATA_PRECISION, roundingMode));
            valueBO.setMonthTotalLy(previousTotal.setScale(BaseConstant.DATA_PRECISION, roundingMode));
            return valueBO;
        }

    }