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

import com.atlassian.bitbucket.mesh.git.builder.AbstractGitProcessBuilder;
import com.atlassian.bitbucket.mesh.git.builder.GitProcess;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilder;
import com.atlassian.bitbucket.mesh.layout.StorageLayout;
import com.atlassian.bitbucket.mesh.repository.Repository;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;

import static java.util.Objects.requireNonNull;

public class DefaultGitCloneBuilder extends AbstractGitProcessBuilder<GitCloneBuilder> implements GitCloneBuilder {

    private final CloneFormat format;
    private final StorageLayout storageLayout;

    private String branch;
    private boolean checkout;
    private String directory;
    private String origin;
    private boolean quiet;
    private boolean shared;
    private String template;

    public DefaultGitCloneBuilder(GitProcessBuilder builder, StorageLayout storageLayout, CloneFormat format) {
        super(builder);

        this.format = format;
        this.storageLayout = storageLayout;

        checkout = !format.isFlagged();
    }

    @Nonnull
    @Override
    public GitCloneBuilder branch(String value) {
        branch = value;

        return self();
    }

    @Nonnull
    @Override
    public GitProcess<Void> build() {
        return buildWithLoggingHandler();
    }

    @Nonnull
    @Override
    public DefaultGitCloneBuilder checkout(boolean value) {
        if (format.isFlagged()) {
            throw new IllegalStateException(StringUtils.capitalize(format.name()) +
                    " clones do not have a work tree and therefore do not allow checkouts");
        }
        checkout = value;

        return self();
    }

    @Nonnull
    @Override
    public GitCloneBuilder directory(@Nonnull Path value) {
        directory = requireNonNull(value, "directory").toAbsolutePath().toString();

        return self();
    }

    @Nonnull
    @Override
    public GitCloneBuilder origin(@Nonnull Path value) {
        return origin(requireNonNull(value, "origin").toAbsolutePath().toString());
    }

    @Nonnull
    @Override
    public GitCloneBuilder origin(@Nonnull Repository value) {
        return origin(requireNonNull(value, "origin").getPath());
    }

    @Nonnull
    @Override
    public GitCloneBuilder origin(@Nonnull String value) {
        origin = requireNonNull(value, "origin");

        return self();
    }

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

        return self();
    }

    @Nonnull
    @Override
    public GitCloneBuilder shared(boolean value) {
        shared = value;

        return self();
    }

    @Nonnull
    @Override
    public GitCloneBuilder template(@Nullable Path value) {
        template = value == null ? null : value.toAbsolutePath().toString();

        return self();
    }

    @Override
    protected void applyArguments() {
        if (format.isFlagged()) {
            builder.argument(format.getFlag());
        } else if (!checkout) {
            //Flagged (bare, mirror) clones don't have a work tree, so --no-checkout has no meaning to them. As a
            //result, the checkout flag is only considered for normal clones.
            builder.argument("--no-checkout");
        }
        if (quiet) {
            builder.argument("--quiet");
        }
        if (shared) {
            builder.argument("--shared");
        }
        if (StringUtils.isNotBlank(template)) {
            builder.argument("--template=" + template);
        }
        if (StringUtils.isNotBlank(branch)) {
            builder.argument("-b")
                    .argument(branch);
        }

        builder.argument(origin)
                .argument(directory);
    }

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