package com.atlassian.bitbucket.mesh.git.revert;

import com.atlassian.bitbucket.mesh.git.AbstractParameters;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilder;
import com.atlassian.bitbucket.mesh.git.ref.Branch;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.util.Person;

import javax.annotation.Nonnull;
import java.util.Optional;

import static java.util.Objects.requireNonNull;

/**
 * This class represents different parameters for the {@link GitProcessBuilder#revert() revert} operation.
 *
 * @since 2.1
 */
public class RevertParameters extends AbstractParameters {

    private final Branch branch;
    private final String commitId;
    private final Person committer;
    private final Integer mergedCommitParentNumber;
    private final Repository repository;
    private final String targetBranch;

    private RevertParameters(Builder builder) {
        super(builder);
        branch = requireNonNull(builder.branch, "branch");
        committer = requireNonNull(builder.committer, "committer");
        commitId = requireNonNull(builder.commitId, "commitId");
        mergedCommitParentNumber = builder.mergedCommitParentNumber;
        repository = requireNonNull(builder.repository, "repository");
        targetBranch = builder.targetBranch;
    }

    /**
     * @return an existing {@link Branch} where the revert commit is to be created unless a
     * {@link #targetBranch target branch} is provided. If the
     * {@link #getTargetBranch() target branch} is not {@link Optional#empty}, then the revert commit should be created
     * on the target branch.
     */
    @Nonnull
    public Branch getBranch() {
        return branch;
    }

    /**
     * @return the ID of the commit to be reverted
     */
    @Nonnull
    public String getCommitId() {
        return commitId;
    }

    /**
     * @return the committer of the revert commit.
     */
    @Nonnull
    public Person getCommitter() {
        return committer;
    }

    /**
     * @return parent number of the merge commit to be considered for reverting, if the {@link #getCommitId() commit} is
     * a merge commit, otherwise {@link Optional#empty()}.
     */
    @Nonnull
    public Optional<Integer> getMergedCommitParentNumber() {
        return Optional.ofNullable(mergedCommitParentNumber);
    }

    /**
     * @return the repository to which the {@link #getCommitId() commit} belongs.
     */
    @Nonnull
    public Repository getRepository() {
        return repository;
    }

    /**
     * @return an {@link Optional} with the new target branch to be created with the revert commit. This branch has to
     * be created from the tip of {@link #getBranch()}.
     */
    @Nonnull
    public Optional<String> getTargetBranch() {
        return Optional.ofNullable(targetBranch);
    }

    public static class Builder extends AbstractBuilder<Builder, RevertParameters> {

        private Branch branch;
        private String commitId;
        private Person committer;
        private Integer mergedCommitParentNumber;
        private Repository repository;
        private String targetBranch;

        public Builder(@Nonnull Repository repository) {
            this.repository = requireNonNull(repository, "repository");
        }

        @Nonnull
        public Builder branch(@Nonnull Branch value) {
            branch = requireNonNull(value, "branch");
            return self();
        }

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

        @Nonnull
        public Builder commitId(@Nonnull String value) {
            commitId = requireNonNull(value, "commitId");
            return self();
        }

        @Nonnull
        public Builder committer(@Nonnull Person value) {
            committer = requireNonNull(value, "committer");
            return self();
        }

        @Nonnull
        public Builder mergedCommitParentNumber(int value) {
            mergedCommitParentNumber = value;
            return self();
        }

        @Nonnull
        public Builder repository(@Nonnull Repository value) {
            repository = requireNonNull(value, "repository");
            return self();
        }

        @Nonnull
        public Builder targetBranch(@Nonnull String value) {
            targetBranch = requireNonNull(value, "targetBranch");
            return self();
        }

        @Nonnull
        @Override
        protected Builder self() {
            return this;
        }
    }
}
