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

import com.atlassian.bitbucket.mesh.git.builder.AbstractGitProcessBuilder;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilder;
import com.atlassian.bitbucket.mesh.repository.Repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

public class DefaultGitFetchBuilder extends AbstractGitProcessBuilder<GitFetchBuilder> implements GitFetchBuilder {

    private final Repository baseRepository;
    private final List<String> negotiationTips;
    private final List<String> refspecs;

    private boolean atomic;
    private boolean force;
    private boolean prune;
    private boolean quiet;
    private boolean progress;
    private String repository;
    private GitFetchTagMode tagMode;

    public DefaultGitFetchBuilder(GitProcessBuilder builder, @Nullable Repository baseRepository) {
        super(builder.command("fetch"));

        this.baseRepository = baseRepository;

        negotiationTips = new ArrayList<>();
        refspecs = new ArrayList<>();
        tagMode = GitFetchTagMode.DEFAULT;
    }

    @Nonnull
    @Override
    public GitFetchBuilder atomic(boolean value) {
        atomic = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder clearNegotiationTips() {
        negotiationTips.clear();

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder clearRefspecs() {
        refspecs.clear();

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder force(boolean value) {
        force = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder negotiationTips(Iterable<String> values) {
        addIfNotBlank(negotiationTips, values);

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder negotiationTips(String value, String... values) {
        addIfNotBlank(negotiationTips, value, values);

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder progress(boolean value) {
        progress = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder prune(boolean value) {
        prune = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder quiet(boolean value) {
        quiet = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder refspec(String value) {
        addIfNotBlank(refspecs, value);

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder refspecs(Iterable<String> values) {
        addIfNotBlank(refspecs, values);

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder refspecs(String value, String... values) {
        addIfNotBlank(refspecs, value, values);

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder repository(Path value) {
        repository = value == null ? null : value.toString();

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder repository(Repository value) {
        if (value == null) {
            return repository((Path) null);
        }

        return repository(baseRepository == null ?
                value.getPath().toAbsolutePath() :
                value.getRelativePath(baseRepository));
    }

    @Nonnull
    @Override
    public GitFetchBuilder repository(String value) {
        repository = value;

        return self();
    }

    @Nonnull
    @Override
    public GitFetchBuilder tags(@Nonnull GitFetchTagMode value) {
        tagMode = requireNonNull(value, "tags");

        return self();
    }

    @Override
    protected void applyArguments() {
        if (atomic) {
            builder.argument("--atomic");
        }
        if (force) {
            builder.argument("--force");
        }
        if (prune) {
            builder.argument("--prune");
        }
        if (quiet) {
            builder.argument("--quiet");
        }
        if (progress) {
            builder.argument("--progress");
        }
        if (tagMode.isFlagged()) {
            builder.argument(tagMode.getFlag());
        }
        for (String negotiationTip : negotiationTips) {
            builder.argument("--negotiation-tip=" + negotiationTip);
        }
        if (isNotBlank(repository)) {
            builder.argument(repository);
            for (String refspec : refspecs) {
                builder.argument(refspec);
            }
        }
    }

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