package cn.axzo.msg.center.service.dto;

import cn.axzo.basics.common.model.IBaseTree;
import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
import cn.axzo.msg.center.service.enums.StatusEnum;
import cn.axzo.msg.center.service.group.response.MessageGroupTreeNodeResponse;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author cold_blade
 * @date 2023/10/14
 * @version 1.0
 */
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GroupTreeNodeDTO implements IBaseTree<GroupTreeNodeDTO, String>, Serializable {

    private static final long serialVersionUID = -3244632155934087302L;

    /**
     * 存储模型的主键id
     */
    private Long nodeId;
    /**
     * 模板分组结点名称
     */
    private String nodeName;
    /**
     * 模板分组结点名称code
     */
    private String nodeCode;
    /**
     * 结点图标
     */
    private String nodeIcon;
    /**
     * 结点类型
     */
    private MessageGroupNodeCategoryEnum category;
    /**
     * 父节点
     */
    private GroupTreeNodeDTO parentNode;
    /**
     * 是否为叶节点
     */
    private Integer isLeaf;
    /**
     * 状态
     */
    private StatusEnum status;
    /**
     * 子节点列表
     */
    @Builder.Default
    private List<GroupTreeNodeDTO> nodeChildren = Lists.newArrayList();

    public void addChild(GroupTreeNodeDTO child) {
        if (Objects.isNull(child)) {
            return;
        }
        if (Objects.isNull(nodeChildren)) {
            nodeChildren = Lists.newArrayList();
        }
        nodeChildren.add(child);
        child.setParentNode(this);
    }

    public boolean contains(MessageGroupNodeCategoryEnum category, String nodeName) {
        if (Objects.isNull(category)) {
            return false;
        }
        if (Objects.equals(this.category, category)) {
            return Objects.equals(this.nodeName, nodeName);
        }
        LinkedList<GroupTreeNodeDTO> stack = new LinkedList<>();
        stack.push(this);
        while (!stack.isEmpty()) {
            GroupTreeNodeDTO node = stack.pop();
            if (Objects.equals(node.category, category) && Objects.equals(node.nodeName, nodeName)) {
                return true;
            }
            stack.addAll(node.getNodeChildren());
        }
        return false;
    }

    @Override
    public String getParentNodeCode() {
        return Optional.ofNullable(parentNode).map(GroupTreeNodeDTO::getNodeCode).orElse(null);
    }

    public void setNodeChildren(List<GroupTreeNodeDTO> nodeChildren) {
        this.nodeChildren = Optional.ofNullable(nodeChildren).orElseGet(Collections::emptyList);
    }

    public MessageGroupTreeNodeResponse toMessageGroupTreeNodeResponse() {
        List<MessageGroupTreeNodeResponse> children = Optional.ofNullable(nodeChildren)
                .map(v -> v.stream().map(GroupTreeNodeDTO::toMessageGroupTreeNodeResponse).collect(Collectors.toList()))
                .orElseGet(Collections::emptyList);
        return MessageGroupTreeNodeResponse.builder()
                .category(category)
                .nodeName(nodeName)
                .nodeCode(nodeCode)
                .parentNodeCode(getParentNodeCode())
                .nodeIcon(nodeIcon)
                .children(children)
                .build();
    }

    public List<GroupTreeNodeDTO> getLeafNodes() {
        if (CollectionUtils.isEmpty(this.nodeChildren)) {
            return Collections.emptyList();
        }
        List<GroupTreeNodeDTO> leafNodes = Lists.newArrayList();
        LinkedList<GroupTreeNodeDTO> stack = new LinkedList<>(this.nodeChildren);
        while (!stack.isEmpty()) {
            GroupTreeNodeDTO node = stack.pop();
            if (CollectionUtils.isEmpty(node.getNodeChildren())) {
                leafNodes.add(node);
            } else {
                stack.addAll(node.getNodeChildren());
            }
        }
        return leafNodes;
    }

    public boolean canMountTemplate() {
        return MessageGroupNodeCategoryEnum.GENERAL_MESSAGE_CATEGORY.equals(this.category)
                || MessageGroupNodeCategoryEnum.PENDING_MESSAGE_CATEGORY.equals(this.category);
    }
}
