package cn.axzo.msg.center.message.service.impl;

import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.msg.center.common.enums.ServiceErrorCodeEnum;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.redis.RedisUtil;
import cn.axzo.msg.center.common.utils.PageHelperUtil;
import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.inside.notices.config.DetailStyleInfo;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO.MessageRouteButtonDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO.MessageRouteDetailDTO;
import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
import cn.axzo.msg.center.service.dto.MessageBaseTemplateDTO;
import cn.axzo.msg.center.service.dto.MessageButtonRouteStrategyDTO;
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.enums.StatusEnum;
import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
import cn.axzo.msg.center.service.template.response.MessageDetailStyle;
import cn.axzo.msg.center.service.template.response.MessageTemplateDetailResponse;
import cn.axzo.msg.center.service.template.response.MessageTemplatePageResponse;
import cn.axzo.msg.center.utils.JSONObjectUtil;
import cn.axzo.msg.center.utils.MessageRouterUtil;
import cn.axzo.msg.center.utils.MessageTemplateCategoryUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import cn.azxo.framework.common.model.Page;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @description
 *
 * @author cold_blade
 * @date 2023/10/5
 * @version 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageTemplateNewServiceImpl implements MessageTemplateNewService {

    private static final String SAVE_TEMPLATE_MUTEX_KEY = "msg-center:template:save:%s";
    private static final long TRY_LOCK_TIMEOUT_MILLS = 1000;
    private static final int RETRY_CNT_MAX = 3;

    private static final int MAX_NUM_ONCE_QUERY = 1000;

    private final RedisUtil redisUtil;
    private final MessageBaseTemplateDao messageBaseTemplateDao;
    private final MessageGroupNodeService messageGroupNodeService;
    private final MessageTemplateGroupService messageTemplateGroupService;
    private final MessageTemplateRouterService messageTemplateRouterService;
    private final PendingMessageBizConfig pendingBizConfig;
    private final GroupTemplateService groupTemplateService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createTemplate(MessageTemplateSaveOrUpdateParam param) {
        // 创建模板基础数据
        String templateCode = saveTemplate(param);
        // 创建模板的路由数据
        saveTemplateRouters(param, templateCode);
        // 创建模板与分类的关联关系数据
        messageTemplateGroupService.templateGroup(templateCode, param.getLeafGroupNodes());
        return templateCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTemplate(MessageTemplateSaveOrUpdateParam param) {
        // 更新模板基础数据
        updateBaseTemplate(param);
        // 更新模板分类信息
        updateTemplateGroupRelation(param);
        // 更新模板路由信息
        updateTemplateRouters(param);
    }

    @Override
    public MessageTemplateDetailResponse detail(String templateCode) {
        if (StringUtils.isBlank(templateCode)) {
            return null;
        }
        MessageBaseTemplate baseTemplate = messageBaseTemplateDao.lambdaQuery()
                .eq(MessageBaseTemplate::getCode, templateCode)
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .one();
        if (Objects.isNull(baseTemplate)) {
            log.info("there is not any template match the templateCode:[{}]", templateCode);
            return null;
        }
        // 获取模板关联分类的path列表
        List<String> groupNodePaths = messageTemplateGroupService.listMessageTemplateGroupPaths(
                Lists.newArrayList(templateCode)).getOrDefault(templateCode, Collections.emptyList());
        // 获取模板配置的路由信息
        MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(templateCode)
                .orElse(null);
        return convert(baseTemplate, groupNodePaths, msgTemplateRouter);
    }

    @Override
    public void updateStatus(Long operatorId, String templateCode, StatusEnum status) {
        if (Objects.isNull(operatorId) || StringUtils.isBlank(templateCode) || Objects.isNull(status)) {
            log.info("the param is invalid. operatorId:[{}], code:[{}], status:[{}]", operatorId, templateCode, status);
            return;
        }
        messageBaseTemplateDao.lambdaUpdate()
                .eq(MessageBaseTemplate::getCode, templateCode)
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .set(MessageBaseTemplate::getStatus, status)
                .set(MessageBaseTemplate::getUpdaterId, operatorId)
                .update();
    }

    @Override
    public Optional<MessageTemplateDTO> queryEnableTemplateByCode(String msgTemplateCode) {
        if (StringUtils.isBlank(msgTemplateCode)) {
            log.info("msgTemplateCode is blank.");
            return Optional.empty();
        }
        MessageBaseTemplate msgBaseTemplate = messageBaseTemplateDao.lambdaQuery()
                .eq(MessageBaseTemplate::getCode, msgTemplateCode)
                .eq(MessageBaseTemplate::getIsDelete, 0)
                .eq(MessageBaseTemplate::getStatus, StatusEnum.ENABLE)
                .one();
        if (Objects.isNull(msgBaseTemplate)) {
            log.info("not find the [{}] template.", msgTemplateCode);
            return Optional.empty();
        }
        // 获取模板的路由配置信息
        MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(msgTemplateCode)
                .orElse(null);
        return Optional.of(MessageTemplateDTO.from(msgBaseTemplate, msgTemplateRouter));
    }

    @Override
    public List<MessageTemplateDTO> listByTemplateCodes(List<String> msgTemplateCodes) {
        if (CollectionUtils.isEmpty(msgTemplateCodes)) {
            log.info("msgTemplateCodes is empty.");
            return Collections.emptyList();
        }
        List<MessageBaseTemplate> msgBaseTemplates = messageBaseTemplateDao.lambdaQuery()
                .in(MessageBaseTemplate::getCode, msgTemplateCodes)
                .eq(MessageBaseTemplate::getIsDelete, 0)
                .list();
        if (Objects.isNull(msgBaseTemplates)) {
            log.info("not find the [{}] templates.", msgTemplateCodes);
            return Collections.emptyList();
        }
        Map<String, MessageTemplateRouterDTO> templateRouterMap = messageTemplateRouterService
                .groupByTemplateCode(msgTemplateCodes);
        return msgBaseTemplates.stream()
                .map(e -> MessageTemplateDTO.from(e, templateRouterMap.get(e.getCode())))
                .collect(Collectors.toList());
    }

    @Override
    public Page<MessageTemplatePageResponse> page(MessageTemplatePageRequest request) {
        IPage<MessageBaseTemplate> result = pageQueryBaseTemplate(request);
        if (Objects.isNull(result)
                || CollectionUtils.isEmpty(result.getRecords())) {
            return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
        }
        List<String> templateCodes = result.getRecords().stream()
                .map(MessageBaseTemplate::getCode)
                .collect(Collectors.toList());
        Map<String, List<String>> groupNodePaths = messageTemplateGroupService
                .listMessageTemplateGroupPaths(templateCodes);
        Map<String, String> codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
                .flatMap(Collection::stream).collect(Collectors.toList()));
        List<MessageTemplatePageResponse> records = result.getRecords().stream()
                .map(e -> convert(e, groupNodePaths, codeNameMap))
                .collect(Collectors.toList());
        return Page.toPage(request.getPage(), request.getPageSize(), result.getTotal(), records);
    }

    @Override
    public Page<MessageBaseTemplateDTO> pageBaseTemplate(MessageTemplatePageRequest request) {
        IPage<MessageBaseTemplate> result = pageQueryBaseTemplate(request);
        if (Objects.isNull(result)
                || CollectionUtils.isEmpty(result.getRecords())) {
            return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
        }
        List<MessageBaseTemplateDTO> records = result.getRecords().stream()
                .map(this::convert)
                .collect(Collectors.toList());
        return Page.toPage(request.getPage(), request.getPageSize(), result.getTotal(), records);
    }

    @Override
    public List<MessageTemplatePageResponse> listByCodes(Collection<String> templateCodes) {
        if (CollectionUtils.isEmpty(templateCodes)) {
            log.info("the templateCodes is empty.");
            return Collections.emptyList();
        }
        AssertUtil.isTrue(templateCodes.size() <= MAX_NUM_ONCE_QUERY, "the collection of templateCodes is too large");
        // 查询模板基础数据
        List<MessageBaseTemplate> records = messageBaseTemplateDao.lambdaQuery()
                .in(MessageBaseTemplate::getCode, templateCodes)
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .list();
        // 查询模板的分类结点编码path
        templateCodes = records.stream().map(MessageBaseTemplate::getCode).collect(Collectors.toList());
        Map<String, List<String>> groupNodePaths = messageTemplateGroupService
                .listMessageTemplateGroupPaths(templateCodes);
        // 将模板分类结点编码path转化为分类名称path
        Map<String, String> codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
                .flatMap(Collection::stream).collect(Collectors.toList()));
        // 转化为页面展示的数据模型
        return records.stream()
                .map(e -> convert(e, groupNodePaths, codeNameMap))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> listTemplateCodesByIds(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            log.info("ids is empty.");
            return Collections.emptyList();
        }
        return messageBaseTemplateDao.lambdaQuery()
                .in(MessageBaseTemplate::getId, ids)
                .select(MessageBaseTemplate::getCode)
                .list().stream()
                .map(MessageBaseTemplate::getCode)
                .collect(Collectors.toList());
    }

    @Override
    public MessageTemplateDetailResponse querySyncMessageTemplate(String templateCode) {
        MessageBaseTemplate baseTemplate = messageBaseTemplateDao.lambdaQuery()
                .eq(MessageBaseTemplate::getCode, templateCode)
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .one();
        if (Objects.isNull(baseTemplate)) {
            log.info("there is not any template match the templateCode:[{}]", templateCode);
            return null;
        }
        // 获取模板配置的路由信息
        MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(templateCode)
                .orElse(null);
        return convert(baseTemplate, null, msgTemplateRouter);
    }

    @Override
    public List<MessageDetailStyle> listTemplateDetailStyles() {
        return new ArrayList<>(pendingBizConfig.getMessageDetailStyles());
    }

    private String saveTemplate(MessageTemplateSaveOrUpdateParam param) {
        String templateCode = UUIDUtil.uuidString();
        MessageBaseTemplate template = convert(param);
        boolean result = doSaveTemplate(template, templateCode);
        int retryCnt = 0;
        while (!result && retryCnt++ < RETRY_CNT_MAX) {
            // 默认重试{@cod RETRY_CNT_MAX}次，若{@code RETRY_CNT_MAX}次后依然失败就报错
            templateCode = UUIDUtil.uuidString();
            result = doSaveTemplate(template, templateCode);
        }
        AssertUtil.isTrue(result, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
        return templateCode;
    }

    public boolean doSaveTemplate(MessageBaseTemplate template, String templateCode) {
        String opKey = String.format(SAVE_TEMPLATE_MUTEX_KEY, templateCode);
        String requestId = UUIDUtil.uuidRawString();
        try {
            boolean lockResult = redisUtil.getLockOps().getLockUntilTimeout(opKey, requestId, TRY_LOCK_TIMEOUT_MILLS);
            AssertUtil.isTrue(lockResult, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
            if (isTemplateExist(templateCode)) {
                return false;
            }
            template.setCode(templateCode);
            messageBaseTemplateDao.save(template);
            return true;
        } finally {
            redisUtil.getLockOps().releaseLock(opKey, requestId);
        }
    }

    private boolean isTemplateExist(String templateCode) {
        return messageBaseTemplateDao.lambdaQuery()
                .eq(MessageBaseTemplate::getCode, templateCode)
                .eq(MessageBaseTemplate::getIsDelete, 0)
                .count() > 0;
    }

    private MessageBaseTemplate convert(MessageTemplateSaveOrUpdateParam param) {
        MessageBaseTemplate template = new MessageBaseTemplate();
        template.setName(param.getTemplateName());
        template.setMsgCategory(param.getMsgCategory());
        template.setTitle(param.getTitle());
        template.setContent(param.getContent());
        template.setDetailStyleCode(param.getDetailStyleCode());
        template.setCardContent(JSONObjectUtil.toJSONString(param.getMsgCardContentItems()));
        template.setIcon(param.getIcon());
        template.setPushTerminal(JSONObjectUtil.toJSONString(param.getPushTerminals()));
        template.setMinAppVersion(param.getMinAppVersion());
        template.setCreatorId(param.getOperatorId());
        template.setUpdaterId(param.getOperatorId());
        template.setCreatePersonId(param.getOperatorId());
        template.setCreatePersonName(param.getOperatorName());
        template.setUpdatePersonId(param.getOperatorId());
        template.setUpdatePersonName(param.getOperatorName());
        template.setPushData(param.getPushData());
        return template;
    }

    public void saveTemplateRouters(MessageTemplateSaveOrUpdateParam param, String templateCode) {
        MessageTemplateRouterDTO templateRouter = buildTemplateRouter(param, templateCode);
        if (templateRouter.isValid()) {
            // 模板配置了路由的场景
            messageTemplateRouterService.saveOrUpdate(templateRouter, false, templateCode);
        }
    }

    private void updateBaseTemplate(MessageTemplateSaveOrUpdateParam param) {
        JSONObject pushData = param.getPushData();
        messageBaseTemplateDao.lambdaUpdate()
                .eq(MessageBaseTemplate::getCode, param.getTemplateCode())
                .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .set(MessageBaseTemplate::getUpdaterId, param.getOperatorId())
                .set(StringUtils.isNotBlank(param.getTemplateName()),
                        MessageBaseTemplate::getName, param.getTemplateName())
                .set(MessageBaseTemplate::getPushTerminal, JSON.toJSONString(param.getPushTerminals()))
                .set(StringUtils.isNotBlank(param.getTitle()), MessageBaseTemplate::getTitle, param.getTitle())
                .set(MessageBaseTemplate::getCardContent, JSONObjectUtil.toJSONString(param.getMsgCardContentItems()))
                .set(MessageBaseTemplate::getContent, param.getContent())
                .set(StringUtils.isNotBlank(param.getDetailStyleCode()),
                        MessageBaseTemplate::getDetailStyleCode, param.getDetailStyleCode())
                .set(MessageBaseTemplate::getUpdatePersonId, param.getOperatorId())
                .set(MessageBaseTemplate::getUpdatePersonName, param.getOperatorName())
                .set(MessageBaseTemplate::getIcon, param.getIcon())
                .set(MessageBaseTemplate::getMinAppVersion, param.getMinAppVersion())
                .set(Objects.nonNull(pushData), MessageBaseTemplate::getPushData,
                        pushData == null ? null : pushData.toJSONString())
                .update();
    }

    private void updateTemplateGroupRelation(MessageTemplateSaveOrUpdateParam param) {
        if (CollectionUtils.isEmpty(param.getLeafGroupNodes())) {
            messageTemplateGroupService.deleteTemplateGroup(param.getTemplateCode());
            return;
        }
        messageTemplateGroupService.updateTemplateGroup(param.getTemplateCode(), param.getLeafGroupNodes());
    }

    private void updateTemplateRouters(MessageTemplateSaveOrUpdateParam param) {
        MessageTemplateRouterDTO templateRouter = buildTemplateRouter(param, param.getTemplateCode());
        boolean isCleanOldFlag = Objects.isNull(param.getBizDetailShowStrategy())
                || CollectionUtils.isEmpty(param.getBizDetailShowStrategy().getTerminals())
                || CollectionUtils.isEmpty(param.getRouters());
        if (templateRouter.isValid() || isCleanOldFlag) {
            // 模板修改了路由的场景
            messageTemplateRouterService.saveOrUpdate(templateRouter, true, param.getTemplateCode());
        }
    }

    private IPage<MessageBaseTemplate> pageQueryBaseTemplate(MessageTemplatePageRequest request) {
        List<String> templateCodes = Lists.newArrayList();
        if (StringUtils.isNotBlank(request.getGroupNodeCode())) {
            templateCodes = groupTemplateService.collectTemplateCodes(request.getGroupNodeCode());
            if (CollectionUtils.isEmpty(templateCodes)) {
                // 入参中的分类没有关联任何模板,直接返回查询结果
                return null;
            }
        }
        if (StringUtils.isNotBlank(request.getTemplateCode())) {
            if (CollectionUtils.isNotEmpty(templateCodes)
                    && !templateCodes.contains(request.getTemplateCode())) {
                // 分页查询的入参中没指定的模板编码与分类映射的模板编码无交集
                return null;
            }
            // 取两者的交集
            templateCodes = Lists.newArrayList(request.getTemplateCode());
        }
        IPage<MessageBaseTemplate> pageRequest = request.toPage();
        String title = request.getTitle();
        if (title != null) {
            title = title.trim();
        }
        String content = request.getContent();
        if (content != null) {
            content = content.trim();
        }

        return messageBaseTemplateDao.lambdaQuery()
                .like(StringUtils.isNotBlank(title), MessageBaseTemplate::getTitle, title)
                .like(StringUtils.isNotBlank(content), MessageBaseTemplate::getContent, content)
                .apply(BooleanUtils.isFalse(request.pushSwitchOn), "(json_extract(push_data, '$.switchOn') is null or json_extract(push_data, '$.switchOn') = false)")
                .apply(BooleanUtils.isTrue(request.pushSwitchOn), "json_extract(push_data, '$.switchOn') = true")
                .like(StringUtils.isNotBlank(request.getTemplateName()),
                        MessageBaseTemplate::getName, request.getTemplateName())
                .in(CollectionUtils.isNotEmpty(templateCodes), MessageBaseTemplate::getCode, templateCodes)
                .in(CollectionUtils.isNotEmpty(request.getCategories()), MessageBaseTemplate::getMsgCategory,
                        request.getCategories())
                .eq(Objects.nonNull(request.getStatus()), MessageBaseTemplate::getStatus, request.getStatus())
                .orderByDesc(MessageBaseTemplate::getCreateAt)
                .page(pageRequest);
    }

    private MessageBaseTemplateDTO convert(MessageBaseTemplate record) {
        return MessageBaseTemplateDTO.builder()
                .name(record.getName())
                .code(record.getCode())
                .msgCategory(record.getMsgCategory())
                .title(record.getTitle())
                .content(record.getContent())
                .cardContentItems(JSONObjectUtil.parseArray(record.getCardContent(), MessageCardContentItemDTO.class))
                .icon(record.getIcon())
                .pushTerminals(JSON.parseArray(record.getPushTerminal(), PushTerminalEnum.class))
                .createTimestamp(record.getCreateAt().getTime())
                .build();
    }

    private MessageTemplatePageResponse convert(MessageBaseTemplate record, Map<String, List<String>> groupNodePaths,
                                                Map<String, String> codeNameMap) {
        MessageDetailStyle styleType = pendingBizConfig
                .findMessageDetailType(record.getDetailStyleCode())
                .orElse(null);
        MessageTemplatePageResponse response = new MessageTemplatePageResponse();
        if (styleType != null) {
            response.setStyleType(styleType);
        } else if (record.getMsgCategory() == MessageCategoryEnum.BIZ_PENDING_MESSAGE) {
            response.setStyleType(new MessageDetailStyle(
                    DetailStyleInfo.BIZ_COMMON_CODE, MessageCategoryEnum.BIZ_PENDING_MESSAGE, "业务待办能用", null));
        } else if (record.getMsgCategory() == MessageCategoryEnum.APPROVAL_PENDING_MESSAGE) {
            response.setStyleType(new MessageDetailStyle(
                    DetailStyleInfo.FLOW_COMMON_CODE, MessageCategoryEnum.APPROVAL_PENDING_MESSAGE, "审批待办能用", null));
        }
        response.setTemplateName(record.getName());
        response.setTemplateCode(record.getCode());
        response.setTitle(record.getTitle());
        response.setContent(record.getContent());
        response.setCategory(record.getMsgCategory());
        response.setStatus(record.getStatus());
        List<String> nodeNamePaths = groupNodePaths.getOrDefault(record.getCode(), Collections.emptyList()).stream()
                .filter(codeNameMap::containsKey)
                .map(codeNameMap::get)
                .collect(Collectors.toList());
        response.setGroupNodeNamePaths(nodeNamePaths);
        response.setCreatePersonId(record.getCreatePersonId());
        response.setCreatePersonName(record.getCreatePersonName());
        response.setUpdatePersonId(record.getUpdatePersonId());
        response.setUpdatePersonName(record.getUpdatePersonName());
        response.setPushData(record.getPushData());
        return response;
    }

    private MessageTemplateDetailResponse convert(MessageBaseTemplate record, List<String> groupNodePaths,
                                                  MessageTemplateRouterDTO msgTemplateRouter) {
        List<String> groupNodeCodes = Lists.newArrayList();
        if (CollUtil.isNotEmpty(groupNodePaths)) {
            // 将path解析中解析出分类结点（路径叶结点）的编码
            groupNodeCodes = groupNodePaths.stream()
                    .map(GroupTreeNodePathDTO::parseLeafNodeCode)
                    .collect(Collectors.toList());
        }
        MessageDetailStyle styleType = pendingBizConfig
                .findMessageDetailType(record.getDetailStyleCode())
                .orElse(null);
        return MessageTemplateDetailResponse.builder()
                .templateName(record.getName())
                .detailStyle(styleType)
                .category(MessageTemplateCategoryUtil.parentCategory(record.getMsgCategory()))
                .subCategory(MessageTemplateCategoryUtil.parseAndReturnSubCategory(record.getMsgCategory()))
                .leafGroupNodes(groupNodeCodes)
                .pushTerminals(JSON.parseArray(record.getPushTerminal(), PushTerminalEnum.class))
                .msgTitle(record.getTitle())
                .msgContent(record.getContent())
                .cardContentItems(JSONObjectUtil.parseArray(record.getCardContent(), MessageCardContentItemDTO.class))
                .msgIcon(record.getIcon())
                .detailStrategy(MessageRouterUtil.fetchBizDetailShowStrategy(msgTemplateRouter).orElse(null))
                .routers(MessageRouterUtil.fetchMessageRouterButtonStrategies(msgTemplateRouter))
                .minAppVersion(record.getMinAppVersion())
                .createTimestamp(record.getCreateAt().getTime())
                .updateTimestamp(record.getUpdateAt().getTime())
                .createPersonId(record.getCreatePersonId())
                .createPersonName(record.getCreatePersonName())
                .updatePersonId(record.getUpdatePersonId())
                .updatePersonName(record.getUpdatePersonName())
                .pushData(record.getPushData())
                .build();
    }

    private MessageTemplateRouterDTO buildTemplateRouter(MessageTemplateSaveOrUpdateParam param, String templateCode) {
        MessageTemplateRouterDTO templateRouter = MessageTemplateRouterDTO.builder().build();
        if (Objects.nonNull(param.getBizDetailShowStrategy())
                && CollectionUtils.isNotEmpty(param.getBizDetailShowStrategy().getTerminals())) {
            MessageRouteDetailDTO detailRouter = MessageRouteDetailDTO.from(param.getBizDetailShowStrategy(), templateCode);
            templateRouter.setRouteDetail(detailRouter);
        }
        if (CollectionUtils.isNotEmpty(param.getRouters())) {
            List<MessageRouteButtonDTO> btnRouters = param.getRouters().stream()
                    .filter(MessageButtonRouteStrategyDTO::isValid)
                    .map(e -> MessageRouteButtonDTO.from(e, templateCode))
                    .collect(Collectors.toList());
            templateRouter.setRouteButtons(btnRouters);
        }
        return templateRouter;
    }
}
