package cn.axzo.msg.center.message.controller;

import cn.axzo.msg.center.message.domain.param.MessageGroupNodeSaveOrUpdateParam;
import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
import cn.axzo.msg.center.service.group.client.MessageGroupClient;
import cn.axzo.msg.center.service.group.request.MessageGroupNodeAddRequest;
import cn.axzo.msg.center.service.group.request.MessageGroupNodeListRequest;
import cn.axzo.msg.center.service.group.request.MessageGroupNodeUpdateRequest;
import cn.axzo.msg.center.service.group.request.MessageGroupQueryRequest;
import cn.axzo.msg.center.service.group.response.MessageGroupNodeBriefResponse;
import cn.axzo.msg.center.service.group.response.MessageGroupTreeNodeResponse;
import cn.axzo.msg.center.utils.TreeHelperUtil;
import cn.azxo.framework.common.model.CommonResponse;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 消息分类管理
 *
 * @author cold_blade
 * @date 2023/10/17
 * @version 1.0
 */
@RestController
@RequiredArgsConstructor
public class MessageGroupController implements MessageGroupClient {

    private final MessageGroupNodeService messageGroupNodeService;

    @Override
    public CommonResponse<Void> addNode(MessageGroupNodeAddRequest request) {
        messageGroupNodeService.addGroupNode(MessageGroupNodeSaveOrUpdateParam.from(request));
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<Void> updateNode(MessageGroupNodeUpdateRequest request) {
        messageGroupNodeService.updateGroupNode(MessageGroupNodeSaveOrUpdateParam.from(request));
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<Void> deleteNode(String nodeCode, Long operatorId) {
        messageGroupNodeService.deleteGroupNode(operatorId, nodeCode);
        return CommonResponse.success();
    }

    @Override
    public CommonResponse<List<MessageGroupTreeNodeResponse>> list(MessageGroupQueryRequest request) {
        List<GroupTreeNodeDTO> trees = messageGroupNodeService.listGroupTree(request.getCategory());
        List<MessageGroupTreeNodeResponse> groupTreeNodes;
        if (StringUtils.isNotBlank(request.getNodeName())) {
            // 根据结点类型为分类类型的结点名称搜索时需要剪枝
            final Function<GroupTreeNodeDTO, Boolean> cutFunc = e ->
                    TreeHelperUtil.containsMountTemplateChild(e, request.getNodeName());
            groupTreeNodes = trees.stream()
                    .map(e -> convertCutTree(e, cutFunc))
                    .filter(e -> CollectionUtils.isNotEmpty(e.getChildren()))
                    .collect(Collectors.toList());
        } else {
            groupTreeNodes = trees.stream()
                    .map(GroupTreeNodeDTO::toMessageGroupTreeNodeResponse)
                    .collect(Collectors.toList());
        }
        return CommonResponse.success(groupTreeNodes);
    }

    @Override
    public CommonResponse<List<MessageGroupTreeNodeResponse>> listCutTree(MessageGroupQueryRequest request) {
        Function<GroupTreeNodeDTO, Boolean> cutFunc;
        if (StringUtils.isBlank(request.getNodeName())) {
            cutFunc = TreeHelperUtil::containsMountTemplateChild;
        } else {
            cutFunc = e -> TreeHelperUtil.containsMountTemplateChild(e, request.getNodeName());
        }
        List<MessageGroupTreeNodeResponse> groupTreeNodes = messageGroupNodeService
                .listGroupTree(request.getCategory()).stream()
                .map(e -> convertCutTree(e, cutFunc))
                .filter(e -> CollectionUtils.isNotEmpty(e.getChildren()))
                .collect(Collectors.toList());
        return CommonResponse.success(groupTreeNodes);
    }

    @Override
    public CommonResponse<List<MessageGroupNodeBriefResponse>> listNodeBriefInfo(MessageGroupNodeListRequest request) {
        List<MessageGroupNodeBriefResponse> groupTreeNodes = messageGroupNodeService
                .listLeafNodes(request.getTerminalType(), request.getGroupCategory()).stream()
                .map(e -> new MessageGroupNodeBriefResponse(e.getNodeName(), e.getNodeCode()))
                .collect(Collectors.toList());
        return CommonResponse.success(groupTreeNodes);
    }

    private MessageGroupTreeNodeResponse convertCutTree(GroupTreeNodeDTO srcRootNode,
                                                        Function<GroupTreeNodeDTO, Boolean> cutFunc) {
        MessageGroupTreeNodeResponse tgtRootNode = convert(srcRootNode);
        if (CollectionUtils.isEmpty(srcRootNode.getNodeChildren())) {
            return tgtRootNode;
        }
        Map<GroupTreeNodeDTO, MessageGroupTreeNodeResponse> map = Maps.newHashMap();
        map.put(srcRootNode, tgtRootNode);
        LinkedList<GroupTreeNodeDTO> stack = new LinkedList<>(srcRootNode.getNodeChildren());
        while (!stack.isEmpty()) {
            GroupTreeNodeDTO node = stack.pop();
            if (cutFunc.apply(node)) {
                MessageGroupTreeNodeResponse child = convert(node);
                map.get(node.getParentNode()).addChild(child);
                map.put(node, child);
                stack.addAll(node.getNodeChildren());
            }
        }
        return tgtRootNode;
    }

    private MessageGroupTreeNodeResponse convert(GroupTreeNodeDTO node) {
        return MessageGroupTreeNodeResponse.builder()
                .category(node.getCategory())
                .nodeName(node.getNodeName())
                .nodeCode(node.getNodeCode())
                .nodeIcon(node.getNodeIcon())
                .parentNodeCode(node.getParentNodeCode())
                .build();
    }
}
