package io.cucumber.cucumberexpressions;

import org.jspecify.annotations.Nullable;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;

import static java.util.Objects.requireNonNull;

final class GroupBuilder {
    private final List<GroupBuilder> groupBuilders = new ArrayList<>();
    private boolean capturing = true;
    private @Nullable String source;
    private final int startIndex;
    private int endIndex;

    GroupBuilder(int startIndex) {
        this.startIndex = startIndex;
    }


    void add(GroupBuilder groupBuilder) {
        groupBuilders.add(groupBuilder);
    }

    Group build(Matcher matcher, Iterator<Integer> groupIndices) {
        int groupIndex = groupIndices.next();
        List<Group> children = new ArrayList<>(groupBuilders.size());
        for (GroupBuilder childGroupBuilder : groupBuilders) {
            children.add(childGroupBuilder.build(matcher, groupIndices));
        }
        return new Group(
                matcher.group(groupIndex), //
                matcher.start(groupIndex),  //
                matcher.end(groupIndex),  //
                children.isEmpty() ? null : children //
        );
    }

    List<Group> toGroups() {
        List<Group> list = new ArrayList<>();
        for (GroupBuilder child : groupBuilders) {
            List<Group> groups = child.toGroups();
            list.add(new Group(
                    child.getSource(),
                    child.getStartIndex(),
                    child.getEndIndex(),
                    groups.isEmpty() ? null : groups));
        }
        return list;
    }

    void setNonCapturing() {
        this.capturing = false;
    }

    boolean isCapturing() {
        return capturing;
    }

    void moveChildrenTo(GroupBuilder groupBuilder) {
        for (GroupBuilder child : groupBuilders) {
            groupBuilder.add(child);
        }
    }

    List<GroupBuilder> getChildren() {
        return groupBuilders;
    }

    String getSource() {
        return requireNonNull(source);
    }

    void setSource(String source) {
        this.source = source;
    }

    int getStartIndex() {
        return startIndex;
    }

    int getEndIndex() {
        return endIndex;
    }

    void setEndIndex(int endIndex) {
        this.endIndex = endIndex;
    }
}
