package com.atlassian.stash.internal.scm.git.command.diff;

import com.atlassian.bitbucket.scm.git.command.GitScmCommandBuilder;
import com.atlassian.bitbucket.scm.git.command.diff.GitDiffBuilder;
import com.atlassian.bitbucket.scm.git.command.diff.GitDiffWhitespace;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;

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

public class DefaultGitDiffBuilder extends AbstractGitDiffCoreBuilder<GitDiffBuilder> implements GitDiffBuilder {

    private String dstPrefix;
    private String srcPrefix;
    private String context;
    private GitDiffWhitespace whitespace;

    public DefaultGitDiffBuilder(GitScmCommandBuilder builder) {
        super(builder.command("diff"));
        whitespace = GitDiffWhitespace.SHOW;
    }

    @Nonnull
    @Override
    public GitDiffBuilder contextLines(int value) {
        checkArgument(value >= 0, "Context value must be a non-negative integer");
        context = Integer.toString(value);

        return self();
    }

    @Nonnull
    @Override
    public GitDiffBuilder defaultContextLines() {
        context = null;

        return self();
    }

    @Nonnull
    @Override
    public GitDiffBuilder dstPrefix(String value) {
        dstPrefix = value;

        return self();
    }

    @Nonnull
    @Override
    public GitDiffBuilder srcPrefix(String value) {
        srcPrefix = value;

        return self();
    }

    @Nonnull
    @Override
    public GitDiffBuilder whitespace(@Nonnull GitDiffWhitespace value) {
        whitespace = checkNotNull(value, "whitespace");

        return self();
    }

    @Override
    protected void applyArguments() {
        super.applyArguments();

        if (context != null) {
            builder.argument("-U" + context); //Unified diff with explicit context
        } else {
            builder.argument("-U"); //Unified diff with default context
        }
        //Use more distinctive prefixes than a/ and b/
        if (StringUtils.isNotBlank(dstPrefix)) {
            builder.argument("--dst-prefix=" + dstPrefix);
        }
        if (StringUtils.isNotBlank(srcPrefix)) {
            builder.argument("--src-prefix=" + srcPrefix);
        }
        if (whitespace.isFlagged()) {
            builder.argument(whitespace.getFlag());
        }

        if (StringUtils.isBlank(ancestor)) {
            //If no ancestor is provided, switch to the git log command. --pretty=format: here eliminates all of the
            //other git log output, leaving just the diff output, and -1 limits output to just the requested rev.
            //
            //Note: This style of under-the-covers command switching is _not_ a behaviour to be emulated! It is an
            //      unfortunate but necessary evil of how git diff works with root commits. In general, the caller
            //      should _know_ which git command to use and use the correct one.
            builder.command("log").argument("--pretty=format:").argument("-1");
        } else {
            builder.argument(ancestor);
        }
        builder.argument(rev);

        applyPaths();
    }

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