package com.atlassian.bitbucket.mesh.git.builder.diff;

import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderSupport;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcDiffOptions;

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

public interface GitDiffCoreBuilder<B extends GitDiffCoreBuilder<B>> extends GitProcessBuilderSupport<B> {

    @Nonnull
    B ancestor(String value);

    /**
     * Applies the provided {@link RpcDiffOptions} to the builder, potentially setting many of the individual properties
     * on this builder in a single call.
     *
     * @param value the options to apply
     * @return {@code this}
     */
    @Nonnull
    B applyOptions(@Nonnull RpcDiffOptions value);

    @Nonnull
    B clearPaths();

    /**
     * Sets the {@link GitDiffColor color} mode for the diff.
     *
     * @param value the {@link GitDiffColor color} mode
     * @return {@code this}
     * @throws NullPointerException if the provided {@code value} is {@code null}
     */
    @Nonnull
    B color(@Nonnull GitDiffColor value);

    /**
     * Sets the number of context lines which should be included in the {@code git diff} output. By default, git uses
     * 3 lines. The provided {@code value} must be greater than or equal to 0, since a negative number of context lines
     * has no meaning. {@link #defaultContextLines()} can be called to restore the default after using a custom value.
     *
     * @param value the number of context lines to include in the diff output, {@code 0} or higher
     * @return {@code this}
     * @throws IllegalArgumentException if the provided {@code value} is negative
     * @see #defaultContextLines()
     */
    @Nonnull
    B contextLines(int value);

    /**
     * Restores the default number of context lines.
     *
     * @return {@code this}
     * @see #contextLines(int)
     */
    @Nonnull
    B defaultContextLines();

    /**
     * Sets the prefix to be used by git when outputing the destination path in a diff header. The default used by git
     * is {@code "b/"}.
     * <pre><code>
     *     diff --git a/file.txt b/file.txt
     *     index 05feec6..898a7b8 100644
     *     --- a/file.txt
     *     +++ b/file.txt
     * </code></pre>
     * Changing this value controls both the {@code b/file.txt} in the {@code diff --git} header and the {@code +++}
     * path after the index details.
     *
     * @param value the prefix to display before the destination path, may be empty or {@code null} to use the default
     * @return {@code this}
     */
    @Nonnull
    B dstPrefix(@Nullable String value);

    /**
     * Sets a flag indicating whether {@code git diff} should output full 40-byte hashes for the content IDs on the
     * "index" header. By default, shortened hashes are shown.
     *
     * @param value {@code true} to display full 40-byte hashes on the index header; otherwise, {@code false} to
     *              display short hashes
     * @return {@code this}
     */
    @Nonnull
    B fullIndex(boolean value);

    @Nonnull
    B path(String value);

    @Nonnull
    B paths(String value, String... values);

    @Nonnull
    B paths(Iterable<String> values);

    /**
     * Sets the {@link GitDiffRenames rename detection} mode for the diff. If the specified mode
     * {@link GitDiffRenames#supportsThreshold() supports a threshold}, the default value is used.
     *
     * @param value the {@link GitDiffRenames rename detection} mode
     * @return {@code this}
     * @throws NullPointerException if the provided {@code value} is {@code null}
     */
    @Nonnull
    B renames(@Nonnull GitDiffRenames value);

    /**
     * Sets the {@link GitDiffRenames rename detection} mode for the diff. If the specified mode
     * {@link GitDiffRenames#supportsThreshold() supports a threshold}, the provided threshold
     * will be used. Otherwise, the provided threshold is ignored.
     * <p>
     * Note: {@code git diff} and {@code git diff-tree} will <i>not</i> allow setting the similarity
     * threshold to 100%; running a command like {@code git diff-tree -C100} ignores the threshold
     * and applies the default 50% threshold instead. As a result, this builder limits the threshold
     * provided to be between 1 and 99, inclusive.
     *
     * @param renames   the {@link GitDiffRenames rename detection} mode
     * @param threshold a similarity threshold between 1% and 99%, or {@code null} to use the default threshold
     * @return {@code this}
     * @throws IllegalArgumentException if the provided threshold is negative, 0 or greater than 99
     * @throws NullPointerException if the provided {@code renames} is {@code null}
     */
    @Nonnull
    B renames(@Nonnull GitDiffRenames renames, Integer threshold);

    @Nonnull
    B rev(String value);

    /**
     * Sets the prefix to be used by git when outputing the source path in a diff header. The default used by git is
     * {@code "a/"}.
     * <pre><code>
     *     diff --git a/file.txt b/file.txt
     *     index 05feec6..898a7b8 100644
     *     --- a/file.txt
     *     +++ b/file.txt
     * </code></pre>
     * Changing this value controls both the {@code a/file.txt} in the {@code diff --git} header and the {@code ---}
     * path after the index details.
     *
     * @param value the prefix to display before the source path, may be empty or {@code null} to use the default
     * @return {@code this}
     */
    @Nonnull
    B srcPrefix(@Nullable String value);

    /**
     * @param value an optional flag to ignore whitespace in the diff
     * @return {@code this}
     * @throws NullPointerException if the provided {@code value} is {@code null}
     */
    @Nonnull
    B whitespace(@Nonnull GitDiffWhitespace value);
}
