package com.atlassian.bitbucket.scm;

import com.atlassian.bitbucket.repository.ResolveRefsRequest;
import com.google.common.collect.ImmutableSet;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Set;

import static java.util.Objects.requireNonNull;

/**
 * Describes which refs to {@link ScmCommandFactory#resolveRefs(ResolveRefsCommandParameters) resolve}.
 * <p>
 * If it is known whether a requested ref is a branch or a tag, the caller is <i>encouraged</i> to use either the
 * {@link Builder#branchId(String)} or {@link Builder#tagId(String)} method to allow the SCM to optimize resolving
 * the ref. If the ref type is unknown, the {@link Builder#refId(String)} method should be used.
 *
 * @since 4.4
 */
public class ResolveRefsCommandParameters extends AbstractCommandParameters {

    private final Set<String> branchIds;
    private final Set<String> refIds;
    private final Set<String> tagIds;

    private ResolveRefsCommandParameters(Builder builder) {
        branchIds = builder.branchIds.build();
        refIds = builder.refIds.build();
        tagIds = builder.tagIds.build();
    }

    /**
     * @return the branch IDs to resolve
     */
    @Nonnull
    public Set<String> getBranchIds() {
        return branchIds;
    }

    /**
     * @return the ref IDs to resolve. Could be branches or tags
     */
    @Nonnull
    public Set<String> getRefIds() {
        return refIds;
    }

    /**
     * @return the tag IDs to resolve
     */
    @Nonnull
    public Set<String> getTagIds() {
        return tagIds;
    }

    public static class Builder {

        private final ImmutableSet.Builder<String> branchIds;
        private final ImmutableSet.Builder<String> refIds;
        private final ImmutableSet.Builder<String> tagIds;

        public Builder() {
            branchIds = ImmutableSet.builder();
            refIds = ImmutableSet.builder();
            tagIds = ImmutableSet.builder();
        }

        /**
         * @param request the request to convert to command parameters
         * @since 4.6
         */
        public Builder(@Nonnull ResolveRefsRequest request) {
            this();

            branchIds(requireNonNull(request, "request").getBranchIds())
                    .refIds(request.getRefIds())
                    .tagIds(request.getTagIds());
        }

        @Nonnull
        public Builder branchId(@Nullable String value) {
            addIf(NOT_BLANK, branchIds, value);

            return this;
        }

        @Nonnull
        public Builder branchIds(@Nullable String value, @Nullable String... moreValues) {
            addIf(NOT_BLANK, branchIds, value, moreValues);

            return this;
        }

        @Nonnull
        public Builder branchIds(@Nullable Iterable<String> values) {
            addIf(NOT_BLANK, branchIds, values);

            return this;
        }

        @Nonnull
        public ResolveRefsCommandParameters build() {
            return new ResolveRefsCommandParameters(this);
        }

        @Nonnull
        public Builder refId(@Nullable String value) {
            addIf(NOT_BLANK, refIds, value);

            return this;
        }

        @Nonnull
        public Builder refIds(@Nullable String value, @Nullable String... moreValues) {
            addIf(NOT_BLANK, refIds, value, moreValues);

            return this;
        }

        @Nonnull
        public Builder refIds(@Nullable Iterable<String> values) {
            addIf(NOT_BLANK, refIds, values);

            return this;
        }

        @Nonnull
        public Builder tagId(@Nullable String value) {
            addIf(NOT_BLANK, tagIds, value);

            return this;
        }

        @Nonnull
        public Builder tagIds(@Nullable String value, @Nullable String... moreValues) {
            addIf(NOT_BLANK, tagIds, value, moreValues);

            return this;
        }

        @Nonnull
        public Builder tagIds(@Nullable Iterable<String> values) {
            addIf(NOT_BLANK, tagIds, values);

            return this;
        }
    }
}
