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

import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.exception.ServiceException;
import cn.axzo.msg.center.dal.MessageGroupNodeDao;
import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
import cn.axzo.msg.center.domain.entity.MessageGroupNode;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
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.param.MessageGroupNodeSaveOrUpdateParam;
import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageGroupTreeNodeCacheService;
import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
import cn.axzo.msg.center.service.enums.AppTerminalTypeEnum;
import cn.axzo.msg.center.service.enums.MessageGroupCategoryEnum;
import cn.axzo.msg.center.utils.TreeHelperUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

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;

/**
 * @author cold_blade
 * @version 1.0
 * @date 2023/10/14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageGroupNodeServiceImpl implements MessageGroupNodeService {

    private final MessageGroupNodeDao messageGroupNodeDao;
    private final MessageTemplateGroupDao messageTemplateGroupDao;
    private final PendingMessageBizConfig pendingMessageBizConfig;
    private final MessageGroupTreeNodeCacheService messageGroupTreeNodeCacheService;

    @Override
    public Map<String, String> groupNodeNamePaths(Collection<String> groupNodeCodePaths) {
        if (CollectionUtils.isEmpty(groupNodeCodePaths)) {
            log.info("leafGroupNodeCodes is empty.");
            return Collections.emptyMap();
        }
        return groupNodeCodePaths.stream()
                .map(GroupTreeNodePathDTO::parseLeafNodeCode)
                .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCodePath,
                        GroupTreeNodePathDTO::getNodeNamePath, (cur, pre) -> cur));
    }

    @Override
    public Map<String, String> leafGroupNodeCodePaths(Collection<String> leafGroupNodeCodes) {
        if (CollectionUtils.isEmpty(leafGroupNodeCodes)) {
            log.info("leafGroupNodeCodes is empty.");
            return Collections.emptyMap();
        }
        return leafGroupNodeCodes.stream()
                .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCode,
                        GroupTreeNodePathDTO::getNodeCodePath, (cur, pre) -> cur));
    }

    @Override
    public Optional<GroupTreeNodePathDTO> queryLeafGroupNodeCodePath(String leafNodeCode) {
        return messageGroupTreeNodeCacheService.queryLeafNodePath(leafNodeCode);
    }

    @Override
    public List<GroupTreeNodePathDTO> leafGroupNodeCodePathsByRootNodeCodes(Collection<String> rootNodeCodes) {
        if (CollectionUtils.isEmpty(rootNodeCodes)) {
            log.info("rootNodeCodes is empty.");
            return Collections.emptyList();
        }
        return rootNodeCodes.stream()
                .flatMap(e -> messageGroupTreeNodeCacheService.listLeafNodePaths(e).stream())
                .collect(Collectors.toList());
    }

    @Override
    public void addGroupNode(MessageGroupNodeSaveOrUpdateParam param) {
        GroupTreeNodeDTO parent = StringUtils.isBlank(param.getParentNodeCode()) ? null :
                messageGroupTreeNodeCacheService.queryNode(param.getParentNodeCode())
                        .orElseThrow(() -> new ServiceException("parentNodeCode is invalid"));
        // 合法性校验
        checkCreateRule(parent, param);
        // 存储
        messageGroupNodeDao.save(convert(param));
        // 刷新缓存
//        messageGroupTreeNodeCacheService.refreshCache();
    }

    @Override
    public void updateGroupNode(MessageGroupNodeSaveOrUpdateParam param) {
        boolean updateResult = messageGroupNodeDao.lambdaUpdate()
                .eq(MessageGroupNode::getCode, param.getNodeCode())
                .eq(MessageGroupNode::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .set(StringUtils.isNotBlank(param.getNodeName()), MessageGroupNode::getName, param.getNodeName())
                .set(StringUtils.isNotBlank(param.getIcon()), MessageGroupNode::getIcon, param.getIcon())
                .set(MessageGroupNode::getUpdaterId, param.getOperatorId())
                .update();
//        if (updateResult) {
//            // 刷新缓存
//            messageGroupTreeNodeCacheService.refreshCache();
//        }
    }

    @Override
    public void deleteGroupNode(Long operatorId, String nodeCode) {
        if (Objects.isNull(operatorId) || StringUtils.isBlank(nodeCode)) {
            log.info("the param is invalid. operatorId:[{}], nodeCode:[{}]", operatorId, nodeCode);
            return;
        }
        // 合法性校验
        checkDeleteRule(nodeCode);
        // 删除结点
        boolean removeResult = messageGroupNodeDao.lambdaUpdate()
                .eq(MessageGroupNode::getCode, nodeCode)
                .remove();
//        if (removeResult) {
//            // 刷新缓存
//            messageGroupTreeNodeCacheService.refreshCache();
//        }
    }

    @Override
    public List<GroupTreeNodeDTO> listGroupTree(MessageGroupCategoryEnum category) {
        return messageGroupTreeNodeCacheService.listAllGroupTree().stream()
                // 分类过滤条件
                .filter(e -> Objects.isNull(category)
                        || category.getMsgGroupNodeCategories().contains(e.getCategory()))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> listGroupTreeRootNodeCodes(MessageGroupCategoryEnum category, AppTerminalTypeEnum appTerminalType) {
        AssertUtil.notNull(category, "category can not be null");
        List<Long> nodeIds = MessageGroupCategoryEnum.PENDING.equals(category) ?
                pendingMessageBizConfig.fetchMessageGroupTreeNodeIds(appTerminalType) : Collections.emptyList();
        return messageGroupTreeNodeCacheService.listAllGroupTree().stream()
                .filter(e -> category.getMsgGroupNodeCategories().contains(e.getCategory()))
                .filter(e -> CollectionUtils.isEmpty(nodeIds) || nodeIds.contains(e.getNodeId()))
                .map(GroupTreeNodeDTO::getNodeCode)
                .collect(Collectors.toList());
    }

    @Override
    public List<GroupTreeNodeDTO> listLeafNodes(AppTerminalTypeEnum appTerminalType, MessageGroupCategoryEnum category) {
        AssertUtil.notNull(category, "category can not be null");
        List<Long> nodeIds = MessageGroupCategoryEnum.PENDING.equals(category) ?
                pendingMessageBizConfig.fetchMessageGroupTreeNodeIds(appTerminalType) : Collections.emptyList();
        return messageGroupTreeNodeCacheService.listAllGroupTree().stream()
                .filter(e -> category.getMsgGroupNodeCategories().contains(e.getCategory()))
                .filter(e -> CollectionUtils.isEmpty(nodeIds) || nodeIds.contains(e.getNodeId()))
                .flatMap(e -> e.getLeafNodes().stream())
                .filter(GroupTreeNodeDTO::canMountTemplate)
                .collect(Collectors.toList());
    }

    private MessageGroupNode convert(MessageGroupNodeSaveOrUpdateParam param) {
        MessageGroupNode groupNode = new MessageGroupNode();
        groupNode.setCode(UUIDUtil.uuidString());
        groupNode.setName(param.getNodeName());
        groupNode.setIcon(param.getIcon());
        groupNode.setCategory(param.getCategory());
        groupNode.setParentCode(param.getParentNodeCode());
        groupNode.setCreatorId(param.getOperatorId());
        groupNode.setUpdaterId(param.getOperatorId());
        if (TreeHelperUtil.isLeafNodeCategory(param.getCategory())) {
            groupNode.setIsLeaf(1);
        }
        return groupNode;
    }

    private void checkCreateRule(GroupTreeNodeDTO parent, MessageGroupNodeSaveOrUpdateParam param) {
        if (Objects.nonNull(parent)) {
            AssertUtil.isTrue(parent.getCategory().getLevel() < param.getCategory().getLevel(), "父节点的类型非法");
        }
    }

    private void checkDeleteRule(String nodeCode) {
        GroupTreeNodeDTO node = messageGroupTreeNodeCacheService.queryNode(nodeCode)
                .orElseThrow(() -> new ServiceException(String.format("未找到指定的结点[%s]", nodeCode)));
        // TODO: [cold_blade] [P2] 异常处理需要检查
        AssertUtil.isEmpty(node.getNodeChildren(), "删除失败！删除前请删除子级！");
        // 校验其结点是否被模板关联
        int cnt = messageTemplateGroupDao.lambdaQuery()
                .like(MessageTemplateGroup::getPath, nodeCode)
                .eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
                .count();
        AssertUtil.isTrue(cnt == 0, "删除失败！删除前请先转移消息模版！");
    }
}
