package top.r3944realms.lib39.core.command;

import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.*;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
import top.r3944realms.lib39.core.command.model.CommandNode;
import top.r3944realms.lib39.core.command.model.CommandPath;
import top.r3944realms.lib39.core.command.model.Parameter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * The interface Command help manager.
 */
public interface ICommandHelpManager {
    /**
     * The constant NEWLINE.
     */
    String NEWLINE = "\n";

    /**
     * Gets id.
     *
     * @return the id
     */
    ResourceLocation getID();

    /**
     * Gets head key.
     *
     * @return the head key
     */
    String getHeadKey();

    /**
     * Gets command head.
     *
     * @return the command head
     */
    default String getCommandHead() {
        return getID().getNamespace();
    }

    /**
     * Init command node.
     *
     * @return the command node
     */
    default CommandNode init() {
        CommandNode root;
        root = new CommandNode(this, getCommandHead(), Component.translatable(Lib39LangKey.Message.HELP_HEADER.getKey(), Component.translatable(getHeadKey())), true);
        root.addChild(new CommandNode(this, "help", Component.translatable(Lib39LangKey.Message.BASIC_HELP.getKey())));
        return root;
    }

    /**
     * Gets cache.
     *
     * @return the cache
     */
    Map<Integer, CommandNode> getCache();

    /**
     * Gets root node.
     *
     * @return the root node
     */
    CommandNode getRootNode();

    /**
     * Register command help.
     *
     * @param commandNode the command node
     * @param description the description
     */
    default void registerCommandHelp(@NotNull CommandNode commandNode, MutableComponent description) {
        registerCommandHelp(commandNode.getFullPath(), description);
    }

    /**
     * Register command help.
     *
     * @param commandNode    the command node
     * @param descriptionKey the description key
     */
    default void registerCommandHelp(@NotNull CommandNode commandNode, String descriptionKey) {
        registerCommandHelp(commandNode.getFullPath(), Component.translatable(descriptionKey));
    }

    /**
     * Register command help.
     *
     * @param commandPath the command path
     */
    default void registerCommandHelp(@NotNull CommandPath commandPath) {
        registerCommandHelp(commandPath.fullPath(), Component.literal(""));
    }

    /**
     * Register command parameters.
     *
     * @param commandPath the command path
     * @param parameters  the parameters
     */
    default void registerCommandParameters(@NotNull CommandPath commandPath, @NotNull Parameter.Builder parameters) {
        registerCommandParameters(commandPath.fullPath(), parameters.build());
    }

    private void registerCommandHelp(@NotNull String commandPath, MutableComponent description) {
        String[] pathParts = commandPath.split(" ");
        CommandNode currentNode = getRootNode();

        int startIndex = pathParts[0].equals(getRootNode().getName()) ? 1 : 0;

        for (int i = startIndex; i < pathParts.length; i++) {
            String part = pathParts[i];
            CommandNode child = currentNode.getChild(part);

            if (child == null) {
                MutableComponent nodeDescription = (i == pathParts.length - 1) ? description : Component.literal("");
                child = new CommandNode(this, part, nodeDescription);
                currentNode.addChild(child);
            }

            currentNode = child;
        }
    }

    /**
     * 註冊命令幫助節點
     *
     * @param builder the builder
     */
    default void registerCommand(@NotNull CommandNode.Builder builder) {
        CommandNode newRoot = builder.build();
        mergeTree(getRootNode(), newRoot);
    }

    /**
     * Merge tree.
     *
     * @param target the target
     * @param source the source
     */
    void mergeTree(@NotNull CommandNode target, @NotNull CommandNode source);

    /**
     * 使用Builder模式註冊命令樹
     *
     * @param builder the builder
     */
    default void registerCommandTree(@NotNull CommandNode.Builder builder) {
        registerCommand(builder);
    }

    /**
     * 使用Builder模式快速註冊命令
     *
     * @param configurator the configurator
     */
    default void registerCommands(@NotNull Consumer<CommandNode.Builder> configurator) {
        CommandNode.Builder builder = CommandNode.Builder.of(this);
        configurator.accept(builder);
        registerCommand(builder);
    }

    /**
     * 根据路径查找节点
     *
     * @param path the path
     * @return the optional
     */
    default Optional<CommandNode> findNode(CommandPath path) {
        CommandNode currentNode = getRootNode();
        String[] segments = path.segments();

        // 跳过根节点（如果路径包含）
        int startIndex = segments[0].equals(getRootNode().getName()) ? 1 : 0;

        for (int i = startIndex; i < segments.length; i++) {
            currentNode = currentNode.getChild(segments[i]);
            if (currentNode == null) {
                return Optional.empty();
            }
        }

        return Optional.of(currentNode);
    }

    /**
     * 检查命令是否存在
     *
     * @param path the path
     * @return the boolean
     */
    default boolean hasCommand(CommandPath path) {
        return findNode(path).isPresent();
    }

    private void registerCommandHelp(String commandPath, String descriptionKey) {
        registerCommandHelp(commandPath, Component.translatable(descriptionKey));
    }

    private void registerCommandHelp(String commandPath) {
        registerCommandHelp(commandPath, Component.literal(""));
    }

    /**
     * 注册命令参数（支持单个参数可选标记，使用*前缀表示必选参数）
     *
     * @param commandPath 命令路径，如 "fpsm tacz dummy"
     * @param parameters  参数列表，如 "*requiredParam", "optionalParam"
     */
    private void registerCommandParameters(@NotNull String commandPath, Parameter... parameters) {
        String[] pathParts = commandPath.split(" ");
        CommandNode currentNode = getRootNode();

        // 遍历命令路径，找到目标节点
        int startIndex = pathParts[0].equals(getRootNode().getName()) ? 1 : 0;

        for (int i = startIndex; i < pathParts.length; i++) {
            String part = pathParts[i];
            CommandNode child = currentNode.getChild(part);

            if (child == null) {
                // 如果节点不存在，创建空描述节点
                child = new CommandNode(this, part, Component.literal(""));
                currentNode.addChild(child);
            }

            currentNode = child;
        }

        // 添加参数，处理可选标记
        for (Parameter param : parameters) {
            currentNode.addParameter(param.name(), param.required());
        }
    }

    /**
     * 动态添加子指令到指定命令路径
     *
     * @param commandPath 命令路径，如 "fpsm map modify"
     * @param childName   子指令名称
     * @param description 子指令描述
     * @return 是否添加成功 boolean
     */
    default boolean addChildCommand(@NotNull String commandPath, String childName, MutableComponent description) {
        String[] pathParts = commandPath.split(" ");
        CommandNode currentNode = getRootNode();

        // 遍历命令路径，找到目标父节点
        for (String part : pathParts) {
            if (!part.equals(currentNode.getName())) {
                CommandNode child = currentNode.getChild(part);
                if (child == null) {
                    // 路径不存在，创建中间节点
                    child = new CommandNode(this, part, Component.literal(""));
                    currentNode.addChild(child);
                }
                currentNode = child;
            }
        }

        // 添加子指令
        CommandNode childNode = new CommandNode(this, childName, description);
        currentNode.addChild(childNode);
        return true;
    }

    /**
     * 构建单个命令节点的显示格式
     *
     * @param node   当前命令节点
     * @param indent 当前缩进
     * @param isRoot 是否为根节点
     * @return 格式化后的命令节点组件
     */
    private @NotNull MutableComponent buildCommandLine(CommandNode node, String indent, boolean isRoot, @Nullable String currentFullPath) {
        if (isRoot) {
            // 根节点特殊处理
            String rootCommand = "/" + node.getName();
            return Component.literal(rootCommand)
                    .withStyle(ChatFormatting.AQUA)
                    .withStyle(Style.EMPTY
                            .withClickEvent(new ClickEvent(
                                    ClickEvent.Action.SUGGEST_COMMAND,
                                    rootCommand + " "
                            ))
                            .withHoverEvent(new HoverEvent(
                                    HoverEvent.Action.SHOW_TEXT,
                                    Component.translatable(Lib39LangKey.Message.HELP_HOVER_COPY_TIP.getKey())
                            ))
                    );
        } else {
            // 构建完整命令路径
            String fullCommand = (currentFullPath != null && !currentFullPath.isEmpty())
                    ? currentFullPath + " " + node.getName()
                    : "/" + getRootNode().getName() + " " + node.getFullPath();

            // 构建建议的命令（带参数占位符）
            String suggestedCommand = buildSuggestedCommand(node, fullCommand);

            // 非根节点：显示命令和描述
            MutableComponent prefix = Component.literal(indent + "└─ ").withStyle(ChatFormatting.GRAY);

            // 命令名称（可点击）
            MutableComponent commandName = Component.literal(node.getName())
                    .withStyle(ChatFormatting.DARK_AQUA)
                    .withStyle(Style.EMPTY
                            .withClickEvent(new ClickEvent(
                                    ClickEvent.Action.SUGGEST_COMMAND,
                                    suggestedCommand
                            ))
                            .withHoverEvent(new HoverEvent(
                                    HoverEvent.Action.SHOW_TEXT,
                                    Component.translatable(Lib39LangKey.Message.HELP_HOVER_COPY_TIP.getKey(), suggestedCommand)
                            ))
                    );

            MutableComponent displayLine = prefix.append(commandName);

            // 添加参数显示（只显示，不添加额外空格）
            if (!node.getParameters().isEmpty()) {
                displayLine.append(Component.literal(" ")); // 命令名和参数之间的空格

                for (int i = 0; i < node.getParameters().size(); i++) {
                    Parameter param = node.getParameters().get(i);
                    if (param.required()) {
                        displayLine.append(Component.literal("<").withStyle(ChatFormatting.GRAY))
                                .append(Component.literal(param.name()).withStyle(ChatFormatting.WHITE))
                                .append(Component.literal(">").withStyle(ChatFormatting.GRAY));
                    } else {
                        displayLine.append(Component.literal("[").withStyle(ChatFormatting.GRAY))
                                .append(Component.literal(param.name()).withStyle(ChatFormatting.WHITE))
                                .append(Component.literal("]").withStyle(ChatFormatting.GRAY));
                    }

                    // 参数之间添加空格（除了最后一个）
                    if (i < node.getParameters().size() - 1) {
                        displayLine.append(Component.literal(" "));
                    }
                }
            }

            // 添加分隔符和描述
            displayLine.append(Component.literal(" - ").withStyle(ChatFormatting.DARK_GRAY))
                    .append(node.getDescription().copy().withStyle(ChatFormatting.GRAY));

            // 如果有子节点，添加展开/折叠按钮
            boolean shouldShowToggle = node.hasChildren() && !node.isLeaf();

            if (shouldShowToggle) {
                String toggleKey = node.isExpanded()
                        ? Lib39LangKey.Message.HELP_NODE_TOGGLE_COLLAPSE.getKey()
                        : Lib39LangKey.Message.HELP_NODE_TOGGLE_EXPAND.getKey();

                MutableComponent toggleButton = Component.literal(" [")
                        .withStyle(ChatFormatting.GRAY)
                        .append(Component.translatable(toggleKey).withStyle(ChatFormatting.YELLOW))
                        .append(Component.literal("]").withStyle(ChatFormatting.GRAY));

                // 为按钮添加点击事件
                toggleButton.withStyle(Style.EMPTY
                        .withClickEvent(new ClickEvent(
                                ClickEvent.Action.RUN_COMMAND,
                                "/" + getCommandHead() + " help toggle " + node.hashCode()
                        ))
                        .withHoverEvent(new HoverEvent(
                                HoverEvent.Action.SHOW_TEXT,
                                Component.translatable(Lib39LangKey.Message.HELP_CLICK_EXPAND.getKey())
                                        .withStyle(ChatFormatting.GRAY)
                        ))
                );

                displayLine.append(toggleButton);
            }

            return displayLine;
        }
    }

    /**
     * 构建建议的命令（包含参数占位符）
     */
    private @NotNull String buildSuggestedCommand(@NotNull CommandNode node, @NotNull String baseCommand) {
        StringBuilder sb = new StringBuilder(baseCommand);

        // 如果有参数，添加参数占位符
        if (!node.getParameters().isEmpty()) {
            for (Parameter param : node.getParameters()) {
                sb.append(" ");
                if (param.required()) {
                    sb.append("<").append(param.name()).append(">");
                } else {
                    sb.append("[").append(param.name()).append("]");
                }
            }
        }

        // 如果是叶子节点且没有参数，添加空格以便继续输入
        if (node.isLeaf() && node.getParameters().isEmpty()) {
            sb.append(" ");
        }

        return sb.toString();
    }

    /**
     * 檢查節點是否應該顯示摺疊信息
     */
    private boolean shouldShowCollapsedInfo(@NotNull CommandNode node) {
        return node.hasChildren() && !node.isExpanded() && !node.getChildren().isEmpty();
    }

    /**
     * 獲取有效的子命令數量（過濾掉空描述的命令）
     */
    private long getValidChildCount(@NotNull CommandNode node) {
        return node.getChildren().stream()
                .filter(child -> !child.getDescription().getString().isEmpty())
                .count();
    }

    /**
     * 遞歸構建命令樹
     */
    private void buildCommandTreeString(@NotNull CommandNode node,
                                        @NotNull String indent,
                                        @Nullable String currentFullPath,
                                        @NotNull List<MutableComponent> result) {
        boolean isRoot = indent.isEmpty();
        MutableComponent commandLine = buildCommandLine(node, indent, isRoot, currentFullPath);
        result.add(commandLine.append(Component.literal(NEWLINE)));

        // 遞歸處理子節點
        String childIndent = indent + "|   ";
        if (node.isExpanded()) {
            String newFullPath = (currentFullPath != null && !currentFullPath.isEmpty())
                    ? currentFullPath + " " + node.getName()
                    : "/" + node.getName();

            for (CommandNode child : node.getChildren()) {
                // 只顯示有描述的子命令
                if (!child.getDescription().getString().isEmpty()) {
                    buildCommandTreeString(child, childIndent, newFullPath, result);
                }
            }
        } else if (shouldShowCollapsedInfo(node)) {
            long childCount = getValidChildCount(node);
            if (childCount > 0) {
                MutableComponent collapsedInfo = Component.literal(indent + "|   " + "└─ ")
                        .withStyle(ChatFormatting.GRAY)
                        .append(Component.translatable(
                                Lib39LangKey.Message.HELP_NODE_EXPAND.getKey(),
                                childCount
                        ).withStyle(ChatFormatting.GRAY));

                collapsedInfo.withStyle(Style.EMPTY
                        .withClickEvent(new ClickEvent(
                                ClickEvent.Action.RUN_COMMAND,
                                "/" + getCommandHead() + " help toggle " + node.hashCode()
                        ))
                        .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable(Lib39LangKey.Message.HELP_CLICK_EXPAND.getKey())))
                );

                result.add(collapsedInfo.append(Component.literal(NEWLINE)));
            }
        }
    }

    /**
     * 获取命令树的字符串表示
     *
     * @return 命令树列表 command tree
     */
    default List<MutableComponent> getCommandTree() {
        List<MutableComponent> result = new ArrayList<>();
        buildCommandTreeString(getRootNode(), "", "", result);
        return result;
    }

    /**
     * 切换指定节点的展开/闭合状态
     *
     * @param hashCode 节点哈希值
     * @return 是否成功切换 boolean
     */
    default boolean toggleNodeExpanded(int hashCode) {
        CommandNode currentNode = getCache().getOrDefault(hashCode, null);
        if (currentNode == null) {
            return false;
        }

        if (currentNode.getChildren().size() <= 1) {
            return false;
        }

        currentNode.toggleExpanded();
        return true;
    }

    /**
     * 构建帮助消息
     *
     * @param header  帮助头部
     * @param entries 帮助条目列表
     * @return the mutable component
     */
    default MutableComponent buildHelpMessage(@NotNull Component header, @NotNull List<MutableComponent> entries) {
        MutableComponent helpMessage = Component.empty();
        // 添加头部
        helpMessage.append(header.copy()).append(NEWLINE);

        // 添加分隔线
        helpMessage.append(Component.literal("\n"));


        // 添加当前页的帮助内容
        if (entries.isEmpty()) {
            helpMessage.append(Component.translatable(Lib39LangKey.Message.HELP_NO_ENTRIES.getKey())).append(NEWLINE);
        } else {
            for (MutableComponent entry : entries) {
                helpMessage.append(entry);
            }
        }

        return helpMessage;
    }

    /**
     * Build command tree help mutable component.
     *
     * @return the mutable component
     */
    default MutableComponent buildCommandTreeHelp() {
        List<MutableComponent> commandTree = getCommandTree();
        return buildHelpMessage(Component.translatable(Lib39LangKey.Message.HELP_HEADER.getKey(), Component.translatable(getHeadKey())), commandTree);
    }

}
