package com.mineplex.studio;

import java.util.ArrayList;
import java.util.List;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.contents.PlainTextContents;
import org.apache.commons.lang3.StringUtils;
import org.jspecify.annotations.NonNull;

public class MineplexComponentUtil {
    private static final char LINE_SPLITTER = '\n';

    private MineplexComponentUtil() {}

    @NonNull private static List<@NonNull MutableComponent> splitContent(
            @NonNull final String text, @NonNull final Style style) {
        final String[] parts = StringUtils.splitPreserveAllTokens(text, LINE_SPLITTER);
        final List<MutableComponent> newComponents = new ArrayList<>(parts.length);
        for (final String part : parts) {
            newComponents.add(Component.literal(part).withStyle(style));
        }
        return newComponents;
    }

    @NonNull private static Component combineComponent(@NonNull final List<MutableComponent> parts) {
        final MutableComponent combined = parts.getFirst();

        for (int index = 1; index < parts.size(); index++) {
            combined.append(parts.get(index));
        }

        return combined;
    }

    private static void flattenComponents(
            @NonNull final List<Component> components,
            @NonNull final List<Component> siblings,
            @NonNull final Style style) {
        for (final Component component : siblings) {
            // Create a combined style with the parent to flatten the siblings into a list
            final Style combinedStyle = component.getStyle().applyTo(style);

            components.add(MutableComponent.create(component.getContents()).withStyle(combinedStyle));

            if (!component.getSiblings().isEmpty()) {
                flattenComponents(components, component.getSiblings(), combinedStyle);
            }
        }
    }

    @NonNull public static List<Component> splitLines(@NonNull final List<Component> components) {
        final List<Component> newLines = new ArrayList<>((int) Math.ceil(components.size() * 1.5));

        final List<MutableComponent> parts = new ArrayList<>();
        final List<Component> componentParts = new ArrayList<>();
        for (final Component component : components) {
            flattenComponents(componentParts, List.of(component), Style.EMPTY);

            for (final Component part : componentParts) {
                // We can only check the content if Components that contain strings
                if (!(part.getContents() instanceof PlainTextContents plainTextContents)) {
                    parts.add(MutableComponent.create(part.getContents()).withStyle(part.getStyle()));
                    continue;
                }

                final String text = plainTextContents.text();

                // If the text is empty, we can directly add the message to the list
                if (text.isEmpty()) {
                    parts.add(MutableComponent.create(part.getContents()).withStyle(part.getStyle()));
                    continue;
                }

                final List<MutableComponent> partComponents = splitContent(text, part.getStyle());
                for (int index = 0; index < partComponents.size(); index++) {
                    if (index != 0 && !parts.isEmpty()) {
                        newLines.add(combineComponent(parts));
                        parts.clear();
                    }

                    parts.add(partComponents.get(index));
                }
            }

            if (!parts.isEmpty()) {
                newLines.add(combineComponent(parts));
            }

            parts.clear();
            componentParts.clear();
        }

        return newLines;
    }
}
