# GmwrHotelKpiViewConfigServiceImpl.java

    package cloud.wconnect.workperformance.service.gmwr.impl;

    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.JsonUtils;
    import cloud.wconnect.workperformance.cons.gmwr.GmwrErrorI18nConstant;
    import cloud.wconnect.workperformance.cons.gmwr.GmwrHotelKpiCategoryEnum;
    import cloud.wconnect.workperformance.cons.hotelkpi.HotelKpiCons;
    import cloud.wconnect.workperformance.entity.gmwr.GmwrHotelKpiViewConfig;
    import cloud.wconnect.workperformance.mapper.gmwr.GmwrHotelKpiViewConfigMapper;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.config.GmwrHotelKpiConfigDetailMetricsDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.config.GmwrHotelKpiConfigItemMetricsDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.config.GmwrHotelKpiConfigMetricsDTO;
    import cloud.wconnect.workperformance.pojo.dto.gmwr.hotelkpi.config.GmwrHotelKpiConfigSaveDTO;
    import cloud.wconnect.workperformance.pojo.dto.hotelkpi.internal.metrics.HotelKpiMetricsConfigInternalDTO;
    import cloud.wconnect.workperformance.service.gmwr.IGmwrHotelKpiViewConfigService;
    import cloud.wconnect.workperformance.service.hotelkpi.internal.IHotelKpiInternalService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.stereotype.Service;

    import jakarta.annotation.Nullable;
    import jakarta.annotation.Resource;
    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     * GM Weekly Report Hotel KPI View Config 服务实现类
     * </p>
     *
     * @author zc
     * @since 2024-10-12
     */
    @Service
    @DS("work_performance")
    public class GmwrHotelKpiViewConfigServiceImpl extends ServiceImpl<GmwrHotelKpiViewConfigMapper, GmwrHotelKpiViewConfig> implements IGmwrHotelKpiViewConfigService {
        @Resource
        private IHotelKpiInternalService hotelKpiInternalService;
        @Resource
        private ObjectMapper objectMapper;

        /**
         * 获取 Hotel KPI 显示配置
         *
         * @param propertyId    资产 id
         * @param category      分类
         * @param categoryTitle 分类标题
         * @return GmwrHotelKpiDetailMetricsConfigDTO 集合
         * @author zc
         * @date 2024/12/30
         */
        @Override
        public List<GmwrHotelKpiConfigItemMetricsDTO> list(int propertyId, int category, String categoryTitle) {
            List<HotelKpiMetricsConfigInternalDTO> metricsConfigList = hotelKpiInternalService.listAllMetrics(propertyId, HotelKpiCons.V1);
            if (CollectionUtils.isEmpty(metricsConfigList)) {
                return Collections.emptyList();
            }

            // 获取 Hotel KPI 显示配置数据
            List<Integer> viewMetricsList = listViewConfig(propertyId, category);

            Map<Integer, List<HotelKpiMetricsConfigInternalDTO>> metricsParentId2Configs = metricsConfigList.stream()
                    .collect(Collectors.groupingBy(HotelKpiMetricsConfigInternalDTO::getParentId));

            Optional<GmwrHotelKpiConfigDetailMetricsDTO> detailMetricsDTOOptional = metricsConfigList.stream()
                    .filter(metrics -> metrics.getParentId() == 0 && metrics.getTitle().equals(categoryTitle))
                    .map(parent0Metrics -> {
                        List<GmwrHotelKpiConfigItemMetricsDTO> items = metricsParentId2Configs.getOrDefault(parent0Metrics.getId(),
                                        Collections.emptyList()).stream()
                                .sorted(Comparator.comparing(HotelKpiMetricsConfigInternalDTO::getSort))
                                .map(parent1Metrics -> {
                                    List<GmwrHotelKpiConfigMetricsDTO> metrics = metricsParentId2Configs.getOrDefault(parent1Metrics.getId(),
                                                    Collections.emptyList()).stream()
                                            .sorted(Comparator.comparing(HotelKpiMetricsConfigInternalDTO::getSort))
                                            .map(childMetrics ->
                                                    GmwrHotelKpiConfigMetricsDTO.builder()
                                                            .metricsType(childMetrics.getMetricsType())
                                                            .title(childMetrics.getTitle())
                                                            .view(viewMetricsList.contains(childMetrics.getMetricsType()))
                                                            .build()
                                            ).toList();
                                    return GmwrHotelKpiConfigItemMetricsDTO.builder()
                                            .title(parent1Metrics.getTitle())
                                            .metrics(metrics)
                                            .build();
                                }).toList();
                        return GmwrHotelKpiConfigDetailMetricsDTO.builder()
                                .title(parent0Metrics.getTitle())
                                .items(items).build();
                    }).findFirst();
            return detailMetricsDTOOptional.isPresent() ? detailMetricsDTOOptional.get().getItems() : Collections.emptyList();
        }

        /**
         * 获取 Hotel KPI 显示配置数据
         *
         * @param propertyId 资产 id
         * @param category   分类
         * @return GmwrHotelKpiViewConfig
         * @author zc
         * @date 2024/12/30
         */
        @Override
        public List<Integer> listViewConfig(int propertyId, @Nullable Integer category) {
            List<GmwrHotelKpiViewConfig> viewConfigList = list(new LambdaQueryWrapper<GmwrHotelKpiViewConfig>()
                    .eq(GmwrHotelKpiViewConfig::getPropertyId, propertyId)
                    .eq(Objects.nonNull(category), GmwrHotelKpiViewConfig::getCategory, category));
            return viewConfigList.stream().map(item ->
                            JsonUtils.convertStringToList(objectMapper, item.getDetail(), Integer.class))
                    .flatMap(Collection::stream).toList();
        }

        /**
         * 获取指定资产下的配置
         *
         * @param propertyId 资产 id
         * @return GmwrHotelKpiViewConfig 配置集合
         * @author zc
         * @date 2025/4/28
         */
        @Override
        public List<GmwrHotelKpiViewConfig> list(int propertyId) {
            return list(new LambdaQueryWrapper<GmwrHotelKpiViewConfig>()
                    .eq(GmwrHotelKpiViewConfig::getPropertyId, propertyId));
        }

        /**
         * 保存 Hotel KPI 显示配置
         *
         * @param propertyId    资产 id
         * @param configSaveDTO 配置
         * @param operatorId    操作人 id
         * @author zc
         * @date 2024/12/30
         */
        @Override
        public void save(int propertyId, GmwrHotelKpiConfigSaveDTO configSaveDTO, int operatorId) {
            String categoryTitle = GmwrHotelKpiCategoryEnum.getTitle(configSaveDTO.getCategory());
            List<HotelKpiMetricsConfigInternalDTO> metricsConfigList = hotelKpiInternalService.listAllMetrics(propertyId, HotelKpiCons.V1);
            Map<Integer, List<HotelKpiMetricsConfigInternalDTO>> metricsParentId2Configs = metricsConfigList.stream()
                    .collect(Collectors.groupingBy(HotelKpiMetricsConfigInternalDTO::getParentId));
            // 获取 Hotel KPI 指定分类的指标类型数据，校验保存的指标类型是否有效
            List<Integer> effectiveMetricsTypeList = metricsConfigList.stream()
                    .filter(metrics -> metrics.getParentId() == 0 && metrics.getTitle().equals(categoryTitle))
                    .map(parent0Metrics -> metricsParentId2Configs.getOrDefault(parent0Metrics.getId(), Collections.emptyList()).stream()
                            .map(parent1Metrics -> metricsParentId2Configs.getOrDefault(parent1Metrics.getId(), Collections.emptyList()).stream()
                                    .map(HotelKpiMetricsConfigInternalDTO::getMetricsType).toList()
                            ).flatMap(Collection::stream).toList()
                    ).flatMap(Collection::stream).toList();
            List<Integer> metricsTypeList = configSaveDTO.getMetrics().stream().distinct().toList();
            if (metricsTypeList.stream().anyMatch(metricsType -> !effectiveMetricsTypeList.contains(metricsType))) {
                throw new BadRequestException(GmwrErrorI18nConstant.HOTEL_KPI_METRICS_TYPE_NOT_EXIST,
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(),
                        "The metrics inconsistent with valid data");
            }

            GmwrHotelKpiViewConfig config = new GmwrHotelKpiViewConfig();
            config.setPropertyId(propertyId);
            config.setCategory(configSaveDTO.getCategory());
            config.setDetail(JsonUtils.convertObjListToString(objectMapper, metricsTypeList));
            config.setUpdatedBy(operatorId);
            config.setUpdatedTime(DateTimeUtils.nowTimestamp());
            baseMapper.insertOrUpdateByUnique(config);
        }
    }