package com.tencent.supersonic.headless.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.tencent.supersonic.common.pojo.DataEvent;
import com.tencent.supersonic.common.pojo.DataItem;
import com.tencent.supersonic.common.pojo.ModelRela;
import com.tencent.supersonic.common.pojo.User;
import com.tencent.supersonic.common.pojo.enums.EventType;
import com.tencent.supersonic.common.pojo.enums.StatusEnum;
import com.tencent.supersonic.common.pojo.enums.TypeEnums;
import com.tencent.supersonic.common.pojo.exception.InvalidArgumentException;
import com.tencent.supersonic.common.util.JsonUtil;
import com.tencent.supersonic.headless.api.pojo.DimValueMap;
import com.tencent.supersonic.headless.api.pojo.MetaFilter;
import com.tencent.supersonic.headless.api.pojo.ModelDetail;
import com.tencent.supersonic.headless.api.pojo.enums.ModelDefineType;
import com.tencent.supersonic.headless.api.pojo.request.DimValueAliasReq;
import com.tencent.supersonic.headless.api.pojo.request.DimensionReq;
import com.tencent.supersonic.headless.api.pojo.request.MetaBatchReq;
import com.tencent.supersonic.headless.api.pojo.request.PageDimensionReq;
import com.tencent.supersonic.headless.api.pojo.response.DataSetResp;
import com.tencent.supersonic.headless.api.pojo.response.DatabaseResp;
import com.tencent.supersonic.headless.api.pojo.response.DimensionResp;
import com.tencent.supersonic.headless.api.pojo.response.ModelResp;
import com.tencent.supersonic.headless.api.pojo.response.SemanticQueryResp;
import com.tencent.supersonic.headless.server.persistence.dataobject.DimensionDO;
import com.tencent.supersonic.headless.server.persistence.mapper.DimensionDOMapper;
import com.tencent.supersonic.headless.server.persistence.repository.DimensionRepository;
import com.tencent.supersonic.headless.server.pojo.DimensionFilter;
import com.tencent.supersonic.headless.server.pojo.DimensionsFilter;
import com.tencent.supersonic.headless.server.pojo.ModelFilter;
import com.tencent.supersonic.headless.server.service.DataSetService;
import com.tencent.supersonic.headless.server.service.DatabaseService;
import com.tencent.supersonic.headless.server.service.DimensionService;
import com.tencent.supersonic.headless.server.service.ModelRelaService;
import com.tencent.supersonic.headless.server.service.ModelService;
import com.tencent.supersonic.headless.server.utils.AliasGenerateHelper;
import com.tencent.supersonic.headless.server.utils.DimensionConverter;
import com.tencent.supersonic.headless.server.utils.NameCheckUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DimensionServiceImpl extends ServiceImpl<DimensionDOMapper, DimensionDO>
        implements DimensionService {

    private final DimensionRepository dimensionRepository;

    private final ModelService modelService;

    private final AliasGenerateHelper aliasGenerateHelper;

    private final DatabaseService databaseService;

    private final ModelRelaService modelRelaService;

    private final DataSetService dataSetService;

    private final ApplicationEventPublisher eventPublisher;

    public DimensionServiceImpl(DimensionRepository dimensionRepository, ModelService modelService,
            AliasGenerateHelper aliasGenerateHelper, DatabaseService databaseService,
            ModelRelaService modelRelaService, DataSetService dataSetService,
            ApplicationEventPublisher eventPublisher) {
        this.modelService = modelService;
        this.dimensionRepository = dimensionRepository;
        this.aliasGenerateHelper = aliasGenerateHelper;
        this.databaseService = databaseService;
        this.modelRelaService = modelRelaService;
        this.dataSetService = dataSetService;
        this.eventPublisher = eventPublisher;
    }

    @Override
    public DimensionResp createDimension(DimensionReq dimensionReq, User user) {
        checkExist(Lists.newArrayList(dimensionReq));
        dimensionReq.createdBy(user.getName());
        DimensionDO dimensionDO = DimensionConverter.convert2DimensionDO(dimensionReq);
        dimensionRepository.createDimension(dimensionDO);
        sendEventBatch(Lists.newArrayList(dimensionDO), EventType.ADD, user);

        // should update modelDetail
        modelService.updateModelByDimAndMetric(dimensionReq.getModelId(),
                Lists.newArrayList(dimensionReq), null, user);

        return DimensionConverter.convert2DimensionResp(dimensionDO);
    }

    @Override
    public void alterDimensionBatch(List<DimensionReq> dimensionReqs, Long modelId, User user)
            throws Exception {
        List<DimensionResp> dimensionResps = getDimensions(modelId);
        // get all dimension in model, only use bizname, because name can be changed to everything
        Map<String, DimensionResp> bizNameMap = dimensionResps.stream()
                .collect(Collectors.toMap(DimensionResp::getBizName, a -> a, (k1, k2) -> k1));

        List<DimensionReq> dimensionToInsert = Lists.newArrayList();

        // look for which dimension need to insert, update, delete
        dimensionReqs.forEach(dimension -> {
            if (!bizNameMap.containsKey(dimension.getBizName())) {
                dimensionToInsert.add(dimension);
            }
        });

        // insert
        if (!CollectionUtils.isEmpty(dimensionToInsert)) {
            createDimensionBatch(dimensionToInsert, user);
        }

    }

    @Override
    public void createDimensionBatch(List<DimensionReq> dimensionReqs, User user) {
        List<DimensionDO> dimensionDOS =
                dimensionReqs.stream().peek(dimension -> dimension.createdBy(user.getName()))
                        .map(DimensionConverter::convert2DimensionDO).collect(Collectors.toList());
        dimensionRepository.createDimensionBatch(dimensionDOS);
        // should update modelDetail as well
        modelService.updateModelByDimAndMetric(dimensionReqs.get(0).getModelId(), dimensionReqs,
                null, user);

        sendEventBatch(dimensionDOS, EventType.ADD, user);
    }

    @Override
    public void updateDimension(DimensionReq dimensionReq, User user) {
        checkExist(Lists.newArrayList(dimensionReq));
        DimensionDO dimensionDO = dimensionRepository.getDimensionById(dimensionReq.getId());
        dimensionReq.updatedBy(user.getName());
        String oldName = dimensionDO.getName();
        DimensionConverter.convert(dimensionDO, dimensionReq);
        dimensionRepository.updateDimension(dimensionDO);
        // should update modelDetail as well
        modelService.updateModelByDimAndMetric(dimensionReq.getModelId(),
                Lists.newArrayList(dimensionReq), null, user);

        if (!oldName.equals(dimensionDO.getName())) {
            sendEvent(getDataItem(dimensionDO), EventType.UPDATE, user.getName());
        }
    }

    @Override
    public void updateDimensionBatch(List<DimensionReq> dimensionReqList, User user) {
        checkExist(dimensionReqList);
        List<DimensionDO> dimensionDOS = dimensionReqList.stream()
                .map(DimensionConverter::convert2DimensionDO).collect(Collectors.toList());
        dimensionRepository.batchUpdate(dimensionDOS);
        // should update modelDetail as well
        modelService.updateModelByDimAndMetric(dimensionReqList.get(0).getModelId(),
                dimensionReqList, null, user);
        sendEventBatch(dimensionDOS, EventType.UPDATE, user);
    }

    @Override
    public void batchUpdateStatus(MetaBatchReq metaBatchReq, User user) {
        if (CollectionUtils.isEmpty(metaBatchReq.getIds())) {
            return;
        }
        DimensionFilter dimensionFilter = new DimensionFilter();
        dimensionFilter.setIds(metaBatchReq.getIds());
        List<DimensionDO> dimensionDOS = dimensionRepository.getDimension(dimensionFilter);
        if (CollectionUtils.isEmpty(dimensionDOS)) {
            return;
        }
        dimensionDOS = dimensionDOS.stream().peek(dimensionDO -> {
            dimensionDO.setStatus(metaBatchReq.getStatus());
            dimensionDO.setUpdatedAt(new Date());
            dimensionDO.setUpdatedBy(user.getName());
        }).collect(Collectors.toList());
        dimensionRepository.batchUpdateStatus(dimensionDOS);
        if (StatusEnum.OFFLINE.getCode().equals(metaBatchReq.getStatus())
                || StatusEnum.DELETED.getCode().equals(metaBatchReq.getStatus())) {
            sendEventBatch(dimensionDOS, EventType.DELETE, user);
        } else if (StatusEnum.ONLINE.getCode().equals(metaBatchReq.getStatus())) {
            sendEventBatch(dimensionDOS, EventType.ADD, user);
        }
    }

    @Override
    public void batchUpdateSensitiveLevel(MetaBatchReq metaBatchReq, User user) {
        if (CollectionUtils.isEmpty(metaBatchReq.getIds())) {
            return;
        }
        DimensionFilter metaFilter = new DimensionFilter();
        metaFilter.setIds(metaBatchReq.getIds());
        List<DimensionDO> dimensionDOS = queryDimension(metaFilter);
        for (DimensionDO dimensionDO : dimensionDOS) {
            dimensionDO.setUpdatedAt(new Date());
            dimensionDO.setUpdatedBy(user.getName());
            dimensionDO.setSensitiveLevel(metaBatchReq.getSensitiveLevel());
        }
        updateBatchById(dimensionDOS);
    }

    @Override
    public void deleteDimension(Long id, User user) {
        DimensionDO dimensionDO = dimensionRepository.getDimensionById(id);
        if (dimensionDO == null) {
            throw new RuntimeException(String.format("the dimension %s not exist", id));
        }
        dimensionDO.setStatus(StatusEnum.DELETED.getCode());
        dimensionDO.setUpdatedAt(new Date());
        dimensionDO.setUpdatedBy(user.getName());
        dimensionRepository.updateDimension(dimensionDO);
        // should update modelDetail
        modelService.deleteModelDetailByDimAndMetric(dimensionDO.getModelId(),
                Lists.newArrayList(dimensionDO), null);
        sendEventBatch(Lists.newArrayList(dimensionDO), EventType.DELETE, user);
    }

    @Override
    public void deleteDimensionBatch(List<Long> idList, User user) {
        DimensionsFilter dimensionFilter = new DimensionsFilter();
        dimensionFilter.setDimensionIds(idList);
        List<DimensionDO> dimensionDOList = dimensionRepository.getDimensions(dimensionFilter);
        if (CollectionUtils.isEmpty(dimensionDOList)) {
            throw new RuntimeException(
                    String.format("the dimension %s not exist", StringUtils.join(",", idList)));
        }
        dimensionDOList.forEach(dimensionDO -> {
            dimensionDO.setStatus(StatusEnum.DELETED.getCode());
            dimensionDO.setUpdatedAt(new Date());
            dimensionDO.setUpdatedBy(user.getName());
        });
        dimensionRepository.batchUpdateStatus(dimensionDOList);
        // should update modelDetail
        modelService.deleteModelDetailByDimAndMetric(dimensionDOList.get(0).getModelId(),
                dimensionDOList, null);
        sendEventBatch(dimensionDOList, EventType.DELETE, user);
    }

    @Override
    public DimensionResp getDimension(String bizName, Long modelId) {
        List<DimensionResp> dimensionResps = getDimensions(modelId);
        if (CollectionUtils.isEmpty(dimensionResps)) {
            return null;
        }
        for (DimensionResp dimensionResp : dimensionResps) {
            if (dimensionResp.getBizName().equalsIgnoreCase(bizName)) {
                return dimensionResp;
            }
        }
        return null;
    }

    @Override
    public DimensionResp getDimension(Long id) {
        DimensionDO dimensionDO = dimensionRepository.getDimensionById(id);
        if (dimensionDO == null) {
            return null;
        }
        return DimensionConverter.convert2DimensionResp(dimensionDO, new HashMap<>());
    }

    @Override
    public PageInfo<DimensionResp> queryDimension(PageDimensionReq pageDimensionReq) {
        DimensionFilter dimensionFilter = new DimensionFilter();
        BeanUtils.copyProperties(pageDimensionReq, dimensionFilter);
        dimensionFilter.setModelIds(pageDimensionReq.getModelIds());
        PageInfo<DimensionDO> dimensionDOPageInfo =
                PageHelper.startPage(pageDimensionReq.getCurrent(), pageDimensionReq.getPageSize())
                        .doSelectPageInfo(() -> queryDimension(dimensionFilter));
        PageInfo<DimensionResp> pageInfo = new PageInfo<>();
        BeanUtils.copyProperties(dimensionDOPageInfo, pageInfo);
        pageInfo.setList(convertList(dimensionDOPageInfo.getList()));
        return pageInfo;
    }

    private List<DimensionDO> queryDimension(DimensionFilter dimensionFilter) {
        return dimensionRepository.getDimension(dimensionFilter);
    }

    @Override
    public List<DimensionResp> queryDimensions(DimensionsFilter dimensionsFilter) {
        List<DimensionDO> dimensions = dimensionRepository.getDimensions(dimensionsFilter);
        return convertList(dimensions);
    }

    @Override
    public List<DimensionResp> getDimensions(MetaFilter metaFilter) {
        DimensionFilter dimensionFilter = new DimensionFilter();
        BeanUtils.copyProperties(metaFilter, dimensionFilter);
        List<DimensionDO> dimensionDOS = dimensionRepository.getDimension(dimensionFilter);
        List<DimensionResp> dimensionResps = convertList(dimensionDOS);

        if (!CollectionUtils.isEmpty(metaFilter.getFieldsDepend())) {
            return filterByField(dimensionResps, metaFilter.getFieldsDepend());
        }
        if (metaFilter.getDataSetId() != null) {
            DataSetResp dataSetResp = dataSetService.getDataSet(metaFilter.getDataSetId());
            return DimensionConverter.filterByDataSet(dimensionResps, dataSetResp);
        }
        return dimensionResps;
    }

    private List<DimensionResp> getDimensions(Long modelId) {
        return getDimensions(new MetaFilter(Lists.newArrayList(modelId)));
    }

    private List<DimensionResp> filterByField(List<DimensionResp> dimensionResps,
            List<String> fields) {
        List<DimensionResp> dimensionFiltered = Lists.newArrayList();
        for (DimensionResp dimensionResp : dimensionResps) {
            for (String field : fields) {
                if (dimensionResp.getExpr().contains(field)) {
                    dimensionFiltered.add(dimensionResp);
                }
            }
        }
        return dimensionFiltered;
    }

    @Override
    public List<DimensionResp> getDimensionInModelCluster(Long modelId) {
        ModelResp modelResp = modelService.getModel(modelId);
        List<ModelRela> modelRelas = modelRelaService.getModelRelaList(modelResp.getDomainId());
        List<Long> modelIds = new ArrayList<>();
        modelIds.add(modelId);
        for (ModelRela modelRela : modelRelas) {
            modelIds.add(modelRela.getFromModelId());
            modelIds.add(modelRela.getToModelId());
        }
        DimensionFilter dimensionFilter = new DimensionFilter();
        dimensionFilter.setModelIds(modelIds);
        return getDimensions(dimensionFilter);
    }

    private List<DimensionResp> convertList(List<DimensionDO> dimensionDOS) {
        List<Long> modelIds =
                dimensionDOS.stream().map(DimensionDO::getModelId).collect(Collectors.toList());
        ModelFilter modelFilter = new ModelFilter(false, modelIds);
        Map<Long, ModelResp> modelMap = modelService.getModelMap(modelFilter);
        List<DimensionResp> dimensionResps = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(dimensionDOS)) {
            dimensionResps = dimensionDOS.stream().map(
                    dimensionDO -> DimensionConverter.convert2DimensionResp(dimensionDO, modelMap))
                    .collect(Collectors.toList());
        }
        return dimensionResps;
    }

    @Override
    public List<String> mockAlias(DimensionReq dimensionReq, String mockType, User user) {
        String mockAlias = aliasGenerateHelper.generateAlias(mockType, dimensionReq.getName(),
                dimensionReq.getBizName(), "", dimensionReq.getDescription());
        String ret = aliasGenerateHelper.extractJsonStringFromAiMessage(mockAlias);
        return JSONObject.parseObject(ret, new TypeReference<List<String>>() {});
    }

    @Override
    public List<DimValueMap> mockDimensionValueAlias(DimensionReq dimensionReq, User user) {
        ModelResp modelResp = modelService.getModel(dimensionReq.getModelId());
        ModelDetail modelDetail = modelResp.getModelDetail();
        String sqlQuery = modelDetail.getSqlQuery();
        if (ModelDefineType.TABLE_QUERY.getName().equals(modelDetail.getQueryType())) {
            String tableQuery = modelDetail.getTableQuery();
            sqlQuery = "SELECT * FROM " + tableQuery;
        }
        DatabaseResp database = databaseService.getDatabase(modelResp.getDatabaseId());

        String sql = "select ai_talk." + dimensionReq.getBizName() + " from (" + sqlQuery
                + ") as ai_talk group by ai_talk." + dimensionReq.getBizName();
        SemanticQueryResp semanticQueryResp = databaseService.executeSql(sql, database);
        List<Map<String, Object>> resultList = semanticQueryResp.getResultList();
        List<String> valueList = new ArrayList<>();
        for (Map<String, Object> stringObjectMap : resultList) {
            String value = String.valueOf(stringObjectMap.get(dimensionReq.getBizName()));
            valueList.add(value);
        }
        String json = aliasGenerateHelper.generateDimensionValueAlias(JSON.toJSONString(valueList));
        log.info("return llm res is :{}", json);
        String ret = aliasGenerateHelper.extractJsonStringFromAiMessage(json);
        JSONObject jsonObject = JSON.parseObject(ret);
        List<DimValueMap> dimValueMapsResp = new ArrayList<>();
        int i = 0;
        for (Map<String, Object> stringObjectMap : resultList) {
            DimValueMap dimValueMap = new DimValueMap();
            dimValueMap.setTechName(String.valueOf(stringObjectMap.get(dimensionReq.getBizName())));
            try {
                String tran = jsonObject.getJSONArray("tran").getString(i);
                dimValueMap.setBizName(tran);
            } catch (Exception exception) {
                dimValueMap.setBizName("");
            }
            try {
                dimValueMap.setAlias(jsonObject.getJSONObject("alias")
                        .getJSONArray(stringObjectMap.get(dimensionReq.getBizName()) + "")
                        .toJavaList(String.class));
            } catch (Exception exception) {
                dimValueMap.setAlias(null);
            }
            dimValueMapsResp.add(dimValueMap);
            i++;
        }
        return dimValueMapsResp;
    }

    private void checkExist(List<DimensionReq> dimensionReqs) {
        Long modelId = dimensionReqs.get(0).getModelId();
        List<DimensionResp> dimensionResps = getDimensions(modelId);
        Map<String, DimensionResp> bizNameMap = dimensionResps.stream()
                .collect(Collectors.toMap(DimensionResp::getBizName, a -> a, (k1, k2) -> k1));
        Map<String, DimensionResp> nameMap = dimensionResps.stream()
                .collect(Collectors.toMap(DimensionResp::getName, a -> a, (k1, k2) -> k1));
        for (DimensionReq dimensionReq : dimensionReqs) {
            String forbiddenCharacters =
                    NameCheckUtils.findForbiddenCharacters(dimensionReq.getName());
            if (StringUtils.isNotBlank(forbiddenCharacters)) {
                throw new InvalidArgumentException(String.format("名称包含特殊字符, 请修改: %s，特殊字符: %s",
                        dimensionReq.getName(), forbiddenCharacters));
            }
            if (bizNameMap.containsKey(dimensionReq.getBizName())) {
                DimensionResp dimensionResp = bizNameMap.get(dimensionReq.getBizName());
                if (!dimensionResp.getId().equals(dimensionReq.getId())) {
                    throw new RuntimeException(String.format("该主题域下存在相同的维度字段名:%s 创建人:%s",
                            dimensionReq.getBizName(), dimensionResp.getCreatedBy()));
                }
            }
            if (nameMap.containsKey(dimensionReq.getName())) {
                DimensionResp dimensionResp = nameMap.get(dimensionReq.getName());
                if (!dimensionResp.getId().equals(dimensionReq.getId())) {
                    throw new RuntimeException(String.format("该主题域下存在相同的维度名:%s 创建人:%s",
                            dimensionReq.getName(), dimensionResp.getCreatedBy()));
                }
            }
        }
    }

    @Override
    public void sendDimensionEventBatch(List<Long> modelIds, EventType eventType, User user) {
        DimensionFilter dimensionFilter = new DimensionFilter();
        dimensionFilter.setModelIds(modelIds);
        List<DimensionDO> dimensionDOS = queryDimension(dimensionFilter);
        sendEventBatch(dimensionDOS, eventType, user);
    }

    private void sendEventBatch(List<DimensionDO> dimensionDOS, EventType eventType, User user) {
        DataEvent dataEvent = getDataEvent(dimensionDOS, eventType, user.getName());
        eventPublisher.publishEvent(dataEvent);
    }

    public DataEvent getAllDataEvents() {
        DimensionFilter dimensionFilter = new DimensionFilter();
        List<DimensionDO> dimensionDOS = queryDimension(dimensionFilter);
        return getDataEvent(dimensionDOS, EventType.ADD, "");
    }

    @Override
    public Boolean updateDimValueAlias(DimValueAliasReq req, User user) {
        DimensionDO dimensionDO = getById(req.getId());
        List<DimValueMap> dimValueMapList = new ArrayList<>();
        if (StringUtils.isNotEmpty(dimensionDO.getDimValueMaps())) {
            dimValueMapList = JsonUtil.toList(dimensionDO.getDimValueMaps(), DimValueMap.class);
        }

        // 预先处理请求列表，设置默认的 techName
        for (DimValueMap dimValueMap : req.getDimValueMaps()) {
            if (StringUtils.isEmpty(dimValueMap.getTechName())) {
                dimValueMap.setTechName(dimValueMap.getValue());
            }
        }

        // 构建现有数据的 Map，用于快速查找 (value -> DimValueMap)
        Map<String, DimValueMap> existingMap = dimValueMapList.stream()
                .collect(Collectors.toMap(DimValueMap::getValue, v -> v, (v1, v2) -> v2));

        // 收集需要删除的 values（alias 为空的）
        Set<String> valuesToDelete = req.getDimValueMaps().stream()
                .filter(dimValueMap -> CollectionUtils.isEmpty(dimValueMap.getAlias()))
                .map(DimValueMap::getValue).collect(Collectors.toSet());

        // 一次性删除所有需要删除的数据
        if (!valuesToDelete.isEmpty()) {
            dimValueMapList =
                    dimValueMapList.stream().filter(map -> !valuesToDelete.contains(map.getValue()))
                            .collect(Collectors.toList());
            // 同时从 existingMap 中移除
            existingMap.keySet().removeAll(valuesToDelete);
        }

        // 处理新增和更新
        for (DimValueMap dimValueMap : req.getDimValueMaps()) {
            // 跳过需要删除的
            if (CollectionUtils.isEmpty(dimValueMap.getAlias())) {
                continue;
            }

            String value = dimValueMap.getValue();
            if (!existingMap.containsKey(value)) {
                // 新增
                dimValueMapList.add(dimValueMap);
                existingMap.put(value, dimValueMap);
            } else {
                // 更新 - 直接更新已存在的对象
                DimValueMap existing = existingMap.get(value);
                existing.setAlias(dimValueMap.getAlias());
                existing.setTechName(dimValueMap.getTechName());
                existing.setBizName(dimValueMap.getBizName());
            }
        }

        dimensionDO.setDimValueMaps(JsonUtil.toString(dimValueMapList));
        updateById(dimensionDO);
        return true;
    }

    private DataItem getDataItem(DimensionDO dimensionDO) {
        ModelResp modelResp = modelService.getModel(dimensionDO.getModelId());
        if (modelResp == null) {
            return null;
        }
        DimensionResp dimensionResp = DimensionConverter.convert2DimensionResp(dimensionDO,
                ImmutableMap.of(modelResp.getId(), modelResp));
        return DataItem.builder().id(dimensionResp.getId().toString()).name(dimensionResp.getName())
                .bizName(dimensionResp.getBizName()).modelId(dimensionResp.getModelId().toString())
                .domainId(dimensionResp.getDomainId().toString()).type(TypeEnums.DIMENSION).build();
    }

    private DataEvent getDataEvent(List<DimensionDO> dimensionDOS, EventType eventType,
            String userName) {
        List<DataItem> dataItems = dimensionDOS.stream().map(this::getDataItem)
                .filter(Objects::nonNull).collect(Collectors.toList());
        return new DataEvent(this, dataItems, eventType, userName);
    }

    private void sendEvent(DataItem dataItem, EventType eventType, String userName) {
        eventPublisher.publishEvent(
                new DataEvent(this, Lists.newArrayList(dataItem), eventType, userName));
    }

    private boolean isChange(DimensionReq dimensionReq, DimensionResp dimensionResp) {
        boolean isNameChange = !dimensionReq.getName().equals(dimensionResp.getName());
        boolean isExtChange = !new EqualsBuilder()
                .append(dimensionReq.getExt(), dimensionResp.getExt()).isEquals();
        boolean isTypeParamChange =
                !Objects.equals(dimensionReq.getTypeParams(), dimensionResp.getTypeParams());
        return isNameChange || isExtChange || isTypeParamChange;
    }
}
