# BudgetDatabaseCommentController.java

    package cloud.wconnect.rateshop.controller.budgetdatabase;

    import cloud.wconnect.commonlib.annotation.ApiId;
    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.CommonErrorI18nConstant;
    import cloud.wconnect.commonlib.exception.BadRequestException;
    import cloud.wconnect.commonlib.util.I18nMessageUtils;
    import cloud.wconnect.rateshop.cons.budgetdatabase.*;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigFbTabItem;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigOtherTabItem;
    import cloud.wconnect.rateshop.entity.budgetdatabase.BudgetDatabaseConfigRoomTabItem;
    import cloud.wconnect.rateshop.pojo.dto.budgetdatabase.SaveCommentDTO;
    import cloud.wconnect.rateshop.service.budgetdatabase.*;
    import com.google.common.collect.Lists;
    import jakarta.validation.Valid;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author yyt
     * @since 2025-09-11
     */
    @RestController
    @RequestMapping("/budget-database/comment")
    public class BudgetDatabaseCommentController {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private I18nMessageUtils i18nMessageUtils;
        @Autowired
        private IBudgetDatabaseConfigRoomTabService budgetDatabaseConfigRoomTabService;
        @Autowired
        private IBudgetDatabaseConfigRoomTabItemService budgetDatabaseConfigRoomTabItemService;
        @Autowired
        private IBudgetDatabaseConfigFbTabService budgetDatabaseConfigFbTabService;
        @Autowired
        private IBudgetDatabaseConfigFbTabItemService budgetDatabaseConfigFbTabItemService;
        @Autowired
        private IBudgetDatabaseConfigOtherTabService budgetDatabaseConfigOtherTabService;
        @Autowired
        private IBudgetDatabaseConfigOtherTabItemService budgetDatabaseConfigOtherTabItemService;
        @Autowired
        private IBudgetDatabaseCommentRoomService budgetDatabaseCommentRoomService;
        @Autowired
        private IBudgetDatabaseCommentFbService budgetDatabaseCommentFbService;
        @Autowired
        private IBudgetDatabaseCommentOtherService budgetDatabaseCommentOtherService;

        /**
         * 1636 - 编辑 Room 分类不同区域的备注
         *
         * @param property    资产
         * @param commentDTOS 备注
         * @return {}
         * @author yyt
         * @date 2025/11/14
         **/
        @ApiId(1636)
        @PostMapping("/room")
        public Map<String, Object> editRoomComment(String property, @Valid @RequestBody List<SaveCommentDTO> commentDTOS) {
            if (CollectionUtils.isEmpty(commentDTOS)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("commentDTOS"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the commentDTOS cannot be empty");
            }

            int propertyId = sessionContext.getPropertyId(property);
            checkRoomParam(propertyId, commentDTOS);

            budgetDatabaseCommentRoomService.save(propertyId, commentDTOS, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 检查 room 参数
         *
         * @param propertyId 资产 id
         * @param commentDTOS 备注
         * @author yyt
         * @date 2025/11/15
         **/
        private void checkRoomParam(int propertyId, List<SaveCommentDTO> commentDTOS) {
            // 验证 tab
            List<Integer> tabIds = commentDTOS.stream().map(SaveCommentDTO::getTabId).distinct().toList();
            if (tabIds.size() > 1) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("tabIds"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the tabIds cannot be repeat");
            }
            Integer tabId = tabIds.get(0);
            budgetDatabaseConfigRoomTabService.checkExist(propertyId, tabId);

            // 验证 area
            List<Integer> area = commentDTOS.stream().map(SaveCommentDTO::getArea).distinct().toList();
            if (RoomCommentAreaCons.MARKET_SEGMENTATION.containsAll(area) || RoomCommentAreaCons.ROOM.containsAll(area)) {
                Map<Boolean, List<Integer>> rowByIsItemId = commentDTOS.stream().map(SaveCommentDTO::getRow)
                        .collect(Collectors.partitioningBy(item -> item > BaseConstant.ZERO));

                List<Integer> itemIds = rowByIsItemId.get(true);
                if (CollectionUtils.isNotEmpty(itemIds)) {
                    if (itemIds.size() != new HashSet<>(itemIds).size()) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("roomIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the roomIds cannot be repeat");
                    }

                    List<BudgetDatabaseConfigRoomTabItem> items = budgetDatabaseConfigRoomTabItemService.listByTabIdAndIds(tabId, itemIds);
                    if (itemIds.size() != items.size()) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("segmentIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the room is not exist");
                    }
                }

                List<Integer> summaryCategoryIds = rowByIsItemId.get(false);
                if (CollectionUtils.isNotEmpty(summaryCategoryIds)) {
                    checkSummaryCategoryIdRepeat(summaryCategoryIds);

                    Set<Integer> rowIds = new HashSet<>(Arrays.stream(RoomTypeEnum.values()).map(RoomTypeEnum::getRowId).toList());
                    if (summaryCategoryIds.stream().anyMatch(item -> !rowIds.contains(item))) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("summaryCategoryIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the summaryCategoryIds is not exist");
                    }
                }
            } else if (new HashSet<>(RoomCommentAreaCons.MONTH_STATISTICS).containsAll(area)) {
                List<Integer> rowIds = commentDTOS.stream().map(SaveCommentDTO::getRow).toList();
                if (rowIds.size() != new HashSet<>(rowIds).size()) {
                    throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                            i18nMessageUtils.getErrorParamMapNotNeedTranslate("rowIds"),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the rowIds cannot be repeat");
                }

                List<Integer> effectiveRowIds = Lists.newArrayList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
                if (rowIds.stream().anyMatch(item -> !effectiveRowIds.contains(item))) {
                    throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                            i18nMessageUtils.getErrorParamMapNotNeedTranslate("summaryCategoryIds"),
                            BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the summaryCategoryIds is not exist");
                }
            } else {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INVALID,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("area"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the area is invalid");
            }
        }

        /**
         * 1637 - 编辑 F&B 分类不同区域的备注
         *
         * @param property    资产
         * @param commentDTOS 备注
         * @return {}
         * @author yyt
         * @date 2025/11/14
         **/
        @ApiId(1637)
        @PostMapping("/fb")
        public Map<String, Object> editFbComment(String property, @Valid @RequestBody List<SaveCommentDTO> commentDTOS) {
            if (CollectionUtils.isEmpty(commentDTOS)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("commentDTOS"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the commentDTOS cannot be empty");
            }

            int propertyId = sessionContext.getPropertyId(property);
            checkFbParam(propertyId, commentDTOS);

            budgetDatabaseCommentFbService.save(propertyId, commentDTOS, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 检查 fb 参数
         *
         * @param propertyId 资产 id
         * @param commentDTOS 备注
         * @author yyt
         * @date 2025/11/15
         **/
        private void checkFbParam(int propertyId, List<SaveCommentDTO> commentDTOS) {
            // 验证 tab
            List<Integer> tabIds = commentDTOS.stream().map(SaveCommentDTO::getTabId).distinct().toList();
            if (tabIds.size() > 1) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("tabIds"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the tabIds cannot be repeat");
            }
            Integer tabId = tabIds.get(0);
            budgetDatabaseConfigFbTabService.checkExist(propertyId, tabId);

            // 验证 area
            List<Integer> area = commentDTOS.stream().map(SaveCommentDTO::getArea).distinct().toList();
            Map<Boolean, List<Integer>> rowByIsFbId = commentDTOS.stream().map(SaveCommentDTO::getRow)
                    .collect(Collectors.partitioningBy(item -> item > BaseConstant.ZERO));

            if (FbCommentAreaCons.FB.containsAll(area)){
                List<Integer> fbIds = rowByIsFbId.get(true);
                if (CollectionUtils.isNotEmpty(fbIds)) {
                    if (fbIds.size() != new HashSet<>(fbIds).size()) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("fbIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the fbIds cannot be repeat");
                    }

                    List<BudgetDatabaseConfigFbTabItem> items = budgetDatabaseConfigFbTabItemService.listByTabIdAndIds(tabId, fbIds);
                    if (items.size() != fbIds.size()){
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("fbIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the fb is not exist");
                    }
                }

                List<Integer> summaryCategoryIds = rowByIsFbId.get(false);
                if (CollectionUtils.isNotEmpty(summaryCategoryIds)) {
                    checkSummaryCategoryIdRepeat(summaryCategoryIds);

                    Set<Integer> rowIds = new HashSet<>(Arrays.stream(FbTypeEnum.values()).map(FbTypeEnum::getRowId).toList());
                    if (summaryCategoryIds.stream().anyMatch(item -> !rowIds.contains(item))) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("summaryCategoryIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the summaryCategoryIds is not exist");
                    }
                }
            } else {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INVALID,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("area"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the area is invalid");
            }

        }

        /**
         * 1638 - 编辑 Other 分类不同区域的备注
         *
         * @param property    资产
         * @param commentDTOS 备注
         * @return {}
         * @author yyt
         * @date 2025/11/14
         **/
        @ApiId(1638)
        @PostMapping("/other")
        public Map<String, Object> editOtherComment(String property, @Valid @RequestBody List<SaveCommentDTO> commentDTOS) {
            if (CollectionUtils.isEmpty(commentDTOS)) {
                throw new BadRequestException(CommonErrorI18nConstant.CANNOT_EMPTY,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("commentDTOS"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the commentDTOS cannot be empty");
            }

            int propertyId = sessionContext.getPropertyId(property);
            checkOtherParam(propertyId, commentDTOS);

            budgetDatabaseCommentOtherService.save(propertyId, commentDTOS, sessionContext.getLoginUserId());

            return Collections.emptyMap();
        }

        /**
         * 检查 other 参数
         *
         * @param propertyId 资产 id
         * @param commentDTOS 备注
         * @author yyt
         * @date 2025/11/15
         **/
        private void checkOtherParam(int propertyId, List<SaveCommentDTO> commentDTOS) {
            // 验证 tab
            List<Integer> tabIds = commentDTOS.stream().map(SaveCommentDTO::getTabId).distinct().toList();
            if (tabIds.size() > 1) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("tabIds"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the tabIds cannot be repeat");
            }
            Integer tabId = tabIds.get(0);
            budgetDatabaseConfigOtherTabService.checkExist(propertyId, tabId);

            // 验证 area
            List<Integer> area = commentDTOS.stream().map(SaveCommentDTO::getArea).distinct().toList();
            Map<Boolean, List<Integer>> rowByIsFbId = commentDTOS.stream().map(SaveCommentDTO::getRow)
                    .collect(Collectors.partitioningBy(item -> item > BaseConstant.ZERO));

            if (OtherCommentAreaCons.OTHER.containsAll(area)){
                List<Integer> otherIds = rowByIsFbId.get(true);
                if (CollectionUtils.isNotEmpty(otherIds)) {
                    if (otherIds.size() != new HashSet<>(otherIds).size()) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("otherIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the otherIds cannot be repeat");
                    }

                    List<BudgetDatabaseConfigOtherTabItem> items = budgetDatabaseConfigOtherTabItemService.listByTabIdAndIds(tabId, otherIds);
                    if (items.size() != otherIds.size()){
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("otherIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the other is not exist");
                    }
                }

                List<Integer> summaryCategoryIds = rowByIsFbId.get(false);
                if (CollectionUtils.isNotEmpty(summaryCategoryIds)) {
                    checkSummaryCategoryIdRepeat(summaryCategoryIds);

                    Set<Integer> rowIds = new HashSet<>(Arrays.stream(FbTypeEnum.values()).map(FbTypeEnum::getRowId).toList());
                    if (summaryCategoryIds.stream().anyMatch(item -> !rowIds.contains(item))) {
                        throw new BadRequestException(CommonErrorI18nConstant.DATA_NOT_EXIST,
                                i18nMessageUtils.getErrorParamMapNotNeedTranslate("summaryCategoryIds"),
                                BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the summaryCategoryIds is not exist");
                    }
                }
            } else {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_INVALID,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("area"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the area is invalid");
            }
        }

        /**
         * 检查 summaryCategoryId 重复
         *
         * @param summaryCategoryIds summaryCategoryIds
         * @author yyt
         * @date 2025/9/17
         **/
        private void checkSummaryCategoryIdRepeat(List<Integer> summaryCategoryIds) {
            if (summaryCategoryIds.size() != new HashSet<>(summaryCategoryIds).size()) {
                throw new BadRequestException(CommonErrorI18nConstant.DATA_CANNOT_REPEAT,
                        i18nMessageUtils.getErrorParamMapNotNeedTranslate("summaryCategoryIds"),
                        BaseErrorCodeEnum.DATA_VALIDATION_ERROR.getCode(), "the summaryCategoryIds cannot be repeat");
            }
        }

    }