package com.atlassian.bitbucket.content;

import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.util.BuilderSupport;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkNotNull;

public class ChangesRequest {

    private final Long pullRequestId;
    private final Repository repository;
    private final String sinceId;
    private final String untilId;
    private final boolean withComments;

    private ChangesRequest(Builder builder) {
        pullRequestId = builder.pullRequestId;
        repository = builder.repository;
        sinceId = builder.sinceId;
        untilId = builder.untilId;
        withComments = builder.withComments;
    }

    /**
     * When comments should be returned as well ({@link #isWithComments()} == {@code true}), a pull request ID can be
     * provided to only retrieve comments that were made in the context of that pull request. If no pull request ID is
     * provided, only comments made outside the context of any pull request will be retrieved.
     *
     * @return the ID for the pull request in which the diff will be displayed
     * @since 4.7
     */
    @Nullable
    public Long getPullRequestId() {
        return pullRequestId;
    }

    @Nonnull
    public Repository getRepository() {
        return repository;
    }

    @Nullable
    public String getSinceId() {
        return sinceId;
    }

    @Nonnull
    public String getUntilId() {
        return untilId;
    }

    /**
     * @return {@code true} if the comment counts associated with the paths in the changes should be included
     * in the response to this request. {@code false} otherwise
     */
    public boolean isWithComments() {
        return withComments;
    }

    public static class Builder extends BuilderSupport {

        private final Repository repository;
        private final String untilId;

        private Long pullRequestId;
        private String sinceId;
        private boolean withComments;

        public Builder(@Nonnull ChangesRequest request) {
            repository = checkNotNull(checkNotNull(request, "request").getRepository(), "request.repository");
            sinceId = StringUtils.trimToNull(request.getSinceId());
            untilId = checkNotBlank(request.getUntilId(), "request.untilId");
            withComments = request.isWithComments();
        }

        public Builder(@Nonnull Repository repository, @Nonnull String untilId) {
            this.repository = checkNotNull(repository, "repository");
            this.untilId = checkNotBlank(untilId, "untilId");

            withComments = true;
        }

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

        @Nonnull
        public Builder pullRequestId(@Nullable Long value) {
            pullRequestId = value;

            return this;
        }

        @Nonnull
        public Builder sinceId(@Nullable String value) {
            sinceId = StringUtils.trimToNull(value);

            return this;
        }

        /**
         * Whether to include comment count information associated to the paths in the changes in the response to the request
         * @param value {@code true} if the comment counts should be included. {@code false} otherwise.
         * @return this builder
         */
        @Nonnull
        public Builder withComments(boolean value) {
            withComments = value;

            return this;
        }
    }
}
