package top.r3944realms.lib39.core.command.model;

import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.core.command.ICommandHelpManager;

import java.util.*;

/**
 * The type Command node.
 */
public class CommandNode {
    private boolean isRoot = false;
    private int hashCache = 0;
    private boolean hashValid = false;
    private final ICommandHelpManager helpManager;
    private final String name;
    private final MutableComponent description;
    private final Map<String, CommandNode> children;

    // 父節點引用，用於構建完整路徑
    @Nullable
    private CommandNode parent;

    // 参数列表，用于存储命令参数
    private final List<Parameter> parameters = new ArrayList<>();

    // 展开/闭合状态
    private boolean expanded = true;

    /**
     * Instantiates a new Command node.
     *
     * @param helpManager the help manager
     * @param name        the name
     * @param description the description
     * @param isRoot      the is root
     */
    public CommandNode(ICommandHelpManager helpManager, String name, MutableComponent description, boolean isRoot) {
        this.name = name;
        this.helpManager = helpManager;
        this.description = description;
        this.children = new TreeMap<>();
        this.isRoot = isRoot;
        invalidateHash();
    }

    /**
     * Instantiates a new Command node.
     *
     * @param helpManager the help manager
     * @param name        the name
     * @param description the description
     */
    public CommandNode(ICommandHelpManager helpManager, String name, MutableComponent description) {
        this.name = name;
        this.helpManager = helpManager;
        this.description = description;
        this.children = new TreeMap<>();
        invalidateHash();
    }

    /**
     * Add child.
     *
     * @param child the child
     */
    public void addChild(CommandNode child) {
        children.put(child.name, child);
        child.parent = this; // 設置父節點引用

        // 如果不是根節點，確保展開狀態正確
        if (!isRoot) {
            this.expanded = false;
        }

        invalidateHash();
    }

    /**
     * Gets child.
     *
     * @param name the name
     * @return the child
     */
    public CommandNode getChild(String name) {
        return children.get(name);
    }

    /**
     * Gets parent.
     *
     * @return the parent
     */
    @Nullable
    public CommandNode getParent() {
        return parent;
    }

    /**
     * Has parent boolean.
     *
     * @return the boolean
     */
    public boolean hasParent() {
        return parent != null;
    }


    /**
     * Gets name.
     *
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * Gets description.
     *
     * @return the description
     */
    public MutableComponent getDescription() {
        return description;
    }

    /**
     * Gets children.
     *
     * @return the children
     */
    public Collection<CommandNode> getChildren() {
        return children.values();
    }

    /**
     * Add parameter.
     *
     * @param parameter the parameter
     * @param required  the required
     */
// 添加参数
    public void addParameter(String parameter, boolean required) {
        parameters.add(new Parameter(parameter, required));
        invalidateHash();
    }

    /**
     * Gets parameters.
     *
     * @return the parameters
     */
// 获取参数列表
    public List<Parameter> getParameters() {
        return parameters;
    }

    /**
     * Is expanded boolean.
     *
     * @return the boolean
     */
// 获取展开状态
    public boolean isExpanded() {
        return expanded;
    }

    /**
     * Sets expanded.
     *
     * @param expanded the expanded
     */
// 设置展开状态
    public void setExpanded(boolean expanded) {
        this.expanded = expanded;
    }

    /**
     * Toggle expanded.
     */
// 切换展开状态
    public void toggleExpanded() {
        this.expanded = !this.expanded;
    }

    @Override
    public int hashCode() {
        return computeHash();
    }

    /**
     * Compute hash int.
     *
     * @return the int
     */
// 计算节点的Hash值
    public int computeHash() {
        if (!hashValid) {
            if (hashCache != 0) {
                helpManager.getCache().remove(hashCache);
            }
            int result = 31;
            result = 31 * result + name.hashCode();
            result = 31 * result + description.getString().hashCode();

            // 计算参数的Hash
            for (Parameter param : parameters) {
                result = 31 * result + param.name().hashCode();
                result = 31 * result + (param.required() ? 1 : 0);
            }

            // 计算子节点的Hash
            for (CommandNode child : children.values()) {
                result = 31 * result + child.computeHash();
            }

            if (!isRoot && children.size() > 1) {
                expanded = false;
            }

            hashCache = result;
            helpManager.getCache().put(result, this);
            hashValid = true;
        }
        return hashCache;
    }

    // 使Hash缓存失效
    private void invalidateHash() {
        hashValid = false;
        computeHash();
    }

    /**
     * 递归构建完整路径
     *
     * @return the full path
     */
    public String getFullPath() {
        if (parent == null) {
            return name;
        }
        return parent.getFullPath() + " " + name;
    }

    /**
     * 獲取完整的命令（以 / 開頭）
     *
     * @return the full command
     */
    public String getFullCommand() {
        if (isRoot) {
            return "/" + name;
        }
        return "/" + getFullPath();
    }

    /**
     * 檢查是否為葉子節點（沒有子節點）
     *
     * @return the boolean
     */
    public boolean isLeaf() {
        return children.isEmpty();
    }

    /**
     * 獲取所有葉子節點（可執行的命令）
     *
     * @return the all leaf nodes
     */
    public List<CommandNode> getAllLeafNodes() {
        List<CommandNode> leaves = new ArrayList<>();
        collectLeafNodes(this, leaves);
        return leaves;
    }

    private void collectLeafNodes(@NotNull CommandNode node, List<CommandNode> leaves) {
        if (node.isLeaf()) {
            leaves.add(node);
        } else {
            for (CommandNode child : node.getChildren()) {
                collectLeafNodes(child, leaves);
            }
        }
    }

    /**
     * 獲取節點路徑（從根節點到當前節點的路徑列表）
     *
     * @return the path segments
     */
    public List<String> getPathSegments() {
        List<String> segments = new ArrayList<>();
        collectPathSegments(this, segments);
        Collections.reverse(segments); // 從根到當前
        return segments;
    }

    private void collectPathSegments(@NotNull CommandNode node, @NotNull List<String> segments) {
        segments.add(node.name);
        if (node.parent != null) {
            collectPathSegments(node.parent, segments);
        }
    }

    /**
     * 比較兩個節點是否在同一路徑上
     *
     * @param other the other
     * @return the boolean
     */
    public boolean isAncestorOf(CommandNode other) {
        CommandNode current = other;
        while (current != null) {
            if (current == this) {
                return true;
            }
            current = current.parent;
        }
        return false;
    }

    /**
     * 獲取最近的共同祖先
     *
     * @param other the other
     * @return the common ancestor
     */
    @Nullable
    public CommandNode getCommonAncestor(CommandNode other) {
        Set<CommandNode> ancestors = new HashSet<>();
        CommandNode current = this;

        // 收集當前節點的所有祖先
        while (current != null) {
            ancestors.add(current);
            current = current.parent;
        }

        // 從另一個節點向上查找
        current = other;
        while (current != null) {
            if (ancestors.contains(current)) {
                return current;
            }
            current = current.parent;
        }

        return null;
    }

    /**
     * 複製節點（不包括子節點）
     *
     * @return the command node
     */
    public CommandNode shallowCopy() {
        CommandNode copy = new CommandNode(helpManager, name, description.copy(), isRoot);
        for (Parameter param : parameters) {
            copy.addParameter(param.name(), param.required());
        }
        copy.expanded = expanded;
        return copy;
    }

    /**
     * 深複製節點（包括所有子節點）
     *
     * @return the command node
     */
    public CommandNode deepCopy() {
        return deepCopy(this, null);
    }

    /**
     * 深複製節點（遞歸複製所有子節點）
     */
    private @NotNull CommandNode deepCopy(@NotNull CommandNode original, @Nullable CommandNode newParent) {
        // 複製當前節點
        CommandNode copy = new CommandNode(helpManager, original.name, original.description.copy(), original.isRoot);
        copy.parent = newParent;
        copy.expanded = original.expanded;

        // 複製參數
        for (Parameter param : original.parameters) {
            copy.addParameter(param.name(), param.required());
        }

        // 遞歸複製子節點
        for (CommandNode child : original.children.values()) {
            CommandNode childCopy = deepCopy(child, copy);
            copy.children.put(childCopy.name, childCopy);
        }

        return copy;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CommandNode that = (CommandNode) o;
        return hashCache == that.hashCache &&
                Objects.equals(name, that.name) &&
                Objects.equals(helpManager, that.helpManager);
    }

    @Override
    public String toString() {
        return String.format("CommandNode{name='%s', path='%s', children=%d, params=%d}",
                name, getFullPath(), children.size(), parameters.size());
    }

    /**
     * The type Builder.
     */
    public static class Builder {
        private final ICommandHelpManager helpManager;
        private final Deque<CommandNode> nodeStack = new ArrayDeque<>();
        private CommandNode root;
        private boolean built = false;

        private Builder(@NotNull final ICommandHelpManager helpManager) {
            this.helpManager = helpManager;
        }

        /**
         * Of builder.
         *
         * @param helpManager the help manager
         * @return the builder
         */
        @Contract(value = "_ -> new", pure = true)
        public static @NotNull Builder of(@NotNull final ICommandHelpManager helpManager) {
            return new Builder(helpManager);
        }

        /**
         * 添加根節點
         *
         * @param name        the name
         * @param description the description
         * @return the builder
         */
        public Builder root(@NotNull String name, @NotNull MutableComponent description) {
            if (root != null) {
                throw new IllegalStateException("Root node already set");
            }
            root = new CommandNode(helpManager, name, description, true);
            nodeStack.push(root);
            return this;
        }

        /**
         * 添加根節點（使用翻譯鍵）
         *
         * @param name           the name
         * @param translationKey the translation key
         * @return the builder
         */
        public Builder root(@NotNull String name, @NotNull String translationKey) {
            return root(name, Component.translatable(translationKey));
        }

        /**
         * 進入子節點（向下移動）
         *
         * @param name        the name
         * @param description the description
         * @return the builder
         */
        public Builder push(@NotNull String name, @NotNull MutableComponent description) {
            checkBuilt();
            if (nodeStack.isEmpty()) {
                throw new IllegalStateException("No parent node available. Call root() first.");
            }

            CommandNode parent = nodeStack.peek();
            CommandNode child = new CommandNode(helpManager, name, description);

            if (!child.isLeaf()) {
                child.setExpanded(false);
            }

            parent.addChild(child);
            nodeStack.push(child);
            return this;
        }

        /**
         * 進入子節點（使用翻譯鍵）
         *
         * @param name           the name
         * @param translationKey the translation key
         * @return the builder
         */
        public Builder push(@NotNull String name, @NotNull String translationKey) {
            return push(name, Component.translatable(translationKey));
        }

        /**
         * 進入子節點並添加參數
         *
         * @param name        the name
         * @param description the description
         * @param parameters  the parameters
         * @return the builder
         */
        public Builder pushWithParams(@NotNull String name, @NotNull MutableComponent description,
                                      @NotNull Parameter... parameters) {
            push(name, description);
            current().addParameters(parameters);
            return this;
        }

        /**
         * 進入子節點並添加必填參數
         *
         * @param name        the name
         * @param description the description
         * @param paramNames  the param names
         * @return the builder
         */
        public Builder pushWithRequiredParams(@NotNull String name, @NotNull MutableComponent description,
                                              @NotNull String @NotNull ... paramNames) {
            push(name, description);
            for (String paramName : paramNames) {
                current().addParameter(paramName, true);
            }
            return this;
        }

        /**
         * 進入子節點並添加可選參數
         *
         * @param name        the name
         * @param description the description
         * @param paramNames  the param names
         * @return the builder
         */
        public Builder pushWithOptionalParams(@NotNull String name, @NotNull MutableComponent description,
                                              @NotNull String @NotNull ... paramNames) {
            push(name, description);
            for (String paramName : paramNames) {
                current().addParameter(paramName, false);
            }
            return this;
        }

        /**
         * 返回上一級節點（向上移動）
         *
         * @return the builder
         */
        public Builder pop() {
            checkBuilt();
            if (nodeStack.size() <= 1) {
                throw new IllegalStateException("Cannot pop root node");
            }
            nodeStack.pop();
            return this;
        }

        /**
         * 返回到根節點
         *
         * @return the builder
         */
        public Builder popToRoot() {
            checkBuilt();
            while (nodeStack.size() > 1) {
                nodeStack.pop();
            }
            return this;
        }

        /**
         * 返回到指定深度的節點
         *
         * @param depth the depth
         * @return the builder
         */
        public Builder popToDepth(int depth) {
            checkBuilt();
            if (depth < 0 || depth >= nodeStack.size()) {
                throw new IllegalArgumentException("Invalid depth: " + depth);
            }
            while (nodeStack.size() > depth + 1) {
                nodeStack.pop();
            }
            return this;
        }

        /**
         * 獲取當前節點
         *
         * @return the command node
         */
        public @NotNull CommandNode current() {
            checkBuilt();
            if (nodeStack.isEmpty()) {
                throw new IllegalStateException("No current node");
            }
            return nodeStack.peek();
        }

        /**
         * 獲取當前深度
         *
         * @return the int
         */
        public int depth() {
            return nodeStack.size() - 1;
        }

        /**
         * 為當前節點添加參數
         *
         * @param name     the name
         * @param required the required
         * @return the builder
         */
        public Builder param(@NotNull String name, boolean required) {
            checkBuilt();
            current().addParameter(name, required);
            return this;
        }

        /**
         * 為當前節點添加必填參數
         *
         * @param name the name
         * @return the builder
         */
        public Builder required(@NotNull String name) {
            return param(name, true);
        }

        /**
         * 為當前節點添加可選參數
         *
         * @param name the name
         * @return the builder
         */
        public Builder optional(@NotNull String name) {
            return param(name, false);
        }

        /**
         * 為當前節點添加多個參數
         *
         * @param parameters the parameters
         * @return the builder
         */
        public Builder params(@NotNull Parameter... parameters) {
            checkBuilt();
            current().addParameters(parameters);
            return this;
        }

        /**
         * 設置當前節點的展開狀態
         *
         * @param expanded the expanded
         * @return the builder
         */
        public Builder expanded(boolean expanded) {
            checkBuilt();
            current().setExpanded(expanded);
            // 如果設置為展開，確保父節點知道
            if (expanded && current().hasParent()) {
                CommandNode parent = current().getParent();
                if (parent != null && !parent.isExpanded()) {
                    parent.setExpanded(true);
                }
            }
            return this;
        }

        /**
         * 添加一個完整的命令分支（鏈式調用）
         *
         * @param name         the name
         * @param description  the description
         * @param configurator the configurator
         * @return the builder
         */
        public Builder branch(@NotNull String name, @NotNull MutableComponent description,
                              @NotNull BranchConfigurator configurator) {
            push(name, description);
            configurator.configure(this);
            pop();
            return this;
        }

        /**
         * 添加一個完整的命令分支（使用翻譯鍵）
         *
         * @param name           the name
         * @param translationKey the translation key
         * @param configurator   the configurator
         * @return the builder
         */
        public Builder branch(@NotNull String name, @NotNull String translationKey,
                              @NotNull BranchConfigurator configurator) {
            return branch(name, Component.translatable(translationKey), configurator);
        }

        /**
         * 快速添加葉子節點（沒有子節點的節點）
         *
         * @param name        the name
         * @param description the description
         * @param parameters  the parameters
         * @return the builder
         */
        public Builder leaf(@NotNull String name, @NotNull MutableComponent description,
                            @NotNull Parameter @NotNull ... parameters) {
            push(name, description);
            if (parameters.length > 0) {
                params(parameters);
            }
            pop();
            return this;
        }

        /**
         * 快速添加葉子節點（使用翻譯鍵）
         *
         * @param name           the name
         * @param translationKey the translation key
         * @param parameters     the parameters
         * @return the builder
         */
        public Builder leaf(@NotNull String name, @NotNull String translationKey,
                            @NotNull Parameter... parameters) {
            return leaf(name, Component.translatable(translationKey), parameters);
        }

        /**
         * 批量添加多個葉子節點
         *
         * @param commands the commands
         * @return the builder
         */
        public Builder leaves(@NotNull Map<String, MutableComponent> commands) {
            for (Map.Entry<String, MutableComponent> entry : commands.entrySet()) {
                leaf(entry.getKey(), entry.getValue());
            }
            return this;
        }

        /**
         * 批量添加多個葉子節點
         *
         * @param commands the commands
         * @return the builder
         */
        public Builder leavesT(@NotNull Map<String, String> commands) {
            for (Map.Entry<String, String> entry : commands.entrySet()) {
                leaf(entry.getKey(), entry.getValue());
            }
            return this;
        }

        /**
         * 批量添加多個帶參數的葉子節點
         *
         * @param commands the commands
         * @return the builder
         */
        public Builder leavesWithParams(@NotNull Map<String, LeafConfig> commands) {
            for (Map.Entry<String, LeafConfig> entry : commands.entrySet()) {
                LeafConfig config = entry.getValue();
                push(entry.getKey(), config.description());
                if (config.parameters() != null && !config.parameters().isEmpty()) {
                    for (Parameter param : config.parameters()) {
                        param(param.name(), param.required());
                    }
                }
                pop();
            }
            return this;
        }

        /**
         * 構建命令樹
         *
         * @return the command node
         */
        public @NotNull CommandNode build() {
            checkBuilt();
            if (root == null) {
                throw new IllegalStateException("Root node not set");
            }
            built = true;
            return root;
        }

        /**
         * 重置構建器（重用）
         *
         * @return the builder
         */
        public Builder reset() {
            nodeStack.clear();
            root = null;
            built = false;
            return this;
        }

        private void checkBuilt() {
            if (built) {
                throw new IllegalStateException("Builder has already been built. Call reset() to reuse.");
            }
        }

        /**
         * 分支配置器接口（用於lambda表達式）
         */
        @FunctionalInterface
        public interface BranchConfigurator {
            /**
             * Configure.
             *
             * @param builder the builder
             */
            void configure(@NotNull Builder builder);
        }

        /**
         * 葉子節點配置記錄
         */
        public record LeafConfig(@NotNull MutableComponent description,
                                 @Nullable List<Parameter> parameters) {

            /**
             * Of leaf config.
             *
             * @param description the description
             * @return the leaf config
             */
            @Contract("_ -> new")
            public static @NotNull LeafConfig of(@NotNull MutableComponent description) {
                return new LeafConfig(description, null);
            }

            /**
             * Of leaf config.
             *
             * @param description the description
             * @param parameters  the parameters
             * @return the leaf config
             */
            @Contract("_, _ -> new")
            public static @NotNull LeafConfig of(@NotNull MutableComponent description,
                                                 @NotNull Parameter... parameters) {
                return new LeafConfig(description, Arrays.asList(parameters));
            }

            /**
             * Of leaf config.
             *
             * @param translationKey the translation key
             * @return the leaf config
             */
            @Contract("_ -> new")
            public static @NotNull LeafConfig of(@NotNull String translationKey) {
                return new LeafConfig(Component.translatable(translationKey), null);
            }

            /**
             * Of leaf config.
             *
             * @param translationKey the translation key
             * @param parameters     the parameters
             * @return the leaf config
             */
            @Contract("_, _ -> new")
            public static @NotNull LeafConfig of(@NotNull String translationKey,
                                                 @NotNull Parameter... parameters) {
                return new LeafConfig(Component.translatable(translationKey), Arrays.asList(parameters));
            }
        }
    }

    // ==================== 新增的輔助方法 ====================

    /**
     * 添加多個參數
     *
     * @param parameters the parameters
     */
    public void addParameters(@NotNull Parameter @NotNull ... parameters) {
        for (Parameter param : parameters) {
            addParameter(param.name(), param.required());
        }
    }

    /**
     * 檢查是否有子節點
     *
     * @return the boolean
     */
    public boolean hasChildren() {
        return !children.isEmpty();
    }

    /**
     * 檢查是否有參數
     *
     * @return the boolean
     */
    public boolean hasParameters() {
        return !parameters.isEmpty();
    }

    /**
     * 獲取節點深度（根節點為0）
     *
     * @return the depth
     */
    public int getDepth() {
        if (isRoot || parent == null) {
            return 0;
        }
        return parent.getDepth() + 1;
    }

    /**
     * 查找子節點（支持遞歸查找）
     *
     * @param path the path
     * @return the command node
     */
    @Nullable
    public CommandNode findChild(@NotNull String @NotNull ... path) {
        if (path.length == 0) {
            return this;
        }

        CommandNode current = this;
        for (String segment : path) {
            current = current.getChild(segment);
            if (current == null) {
                return null;
            }
        }

        return current;
    }

    /**
     * 獲取完整的命令（用於點擊建議）
     *
     * @return the suggested command
     */
    public String getSuggestedCommand() {
        StringBuilder sb = new StringBuilder(getFullCommand());

        // 如果有參數，添加參數佔位符
        for (Parameter param : parameters) {
            sb.append(" ");
            if (param.required()) {
                sb.append("<").append(param.name()).append(">");
            } else {
                sb.append("[").append(param.name()).append("]");
            }
        }

        // 如果沒有子節點且沒有參數，添加空格以便繼續輸入
        if (children.isEmpty() && parameters.isEmpty()) {
            sb.append(" ");
        }

        return sb.toString();
    }

    /**
     * 獲取根節點
     *
     * @return the root
     */
    public CommandNode getRoot() {
        if (isRoot) {
            return this;
        }
        if (parent == null) {
            throw new IllegalStateException("Node has no parent but is not marked as root");
        }
        return parent.getRoot();
    }

}
