package com.atlassian.bitbucket.scm;

import com.atlassian.bitbucket.repository.*;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
import com.atlassian.bitbucket.util.PageRequestImpl;

import java.io.IOException;
import java.io.UncheckedIOException;

/**
 * Default implementation that streams branches using existing {@link PluginCommandFactory} functionality.
 * <p>
 * This class exists only to provide a default implementation for
 * {@link PluginCommandFactory#branches(Repository, BranchesCommandParameters, BranchCallback)} and will be removed
 * in 5.0 when that default implementation is removed.
 *
 * @since 4.6
 * @deprecated in 4.6 for removal in 5.0
 */
@Deprecated
class CompatibilityStreamBranchesCommand extends AbstractCompatibilityCommand<Void> {

    private final BranchCallback callback;
    private final PluginCommandFactory commandFactory;
    private final BranchesCommandParameters parameters;
    private final Repository repository;

    CompatibilityStreamBranchesCommand(PluginCommandFactory commandFactory, Repository repository,
                                       BranchesCommandParameters parameters, BranchCallback callback) {
        this.callback = callback;
        this.commandFactory = commandFactory;
        this.parameters = parameters;
        this.repository = repository;
    }

    @Override
    public Void call() {
        boolean end = false;
        try {
            callback.onStart(new BranchContext.Builder().build());
            end = true; //If we call onStart, the callback contract stipulates we have to call onEnd

            streamBranches();

            end = false; //We only want to call onEnd once; if it throws here, don't call it again
            callback.onEnd(new BranchSummary.Builder(CommandResult.SUCCEEDED).build());
        } catch (IOException e) {
            if (end) {
                try {
                    callback.onEnd(new BranchSummary.Builder(CommandResult.FAILED).build());
                } catch (IOException suppressed) {
                    e.addSuppressed(suppressed);
                }
            }

            //TODO: This should probably throw a CommandFailedException, but it needs the I18nService
            throw new UncheckedIOException(e);
        }

        return null;
    }

    private void streamBranches() throws IOException {
        PageRequest pageRequest = new PageRequestImpl(0, 500);
        while (true) {
            Page<Branch> page = configureAndCall(commandFactory.branches(repository, parameters, pageRequest));
            if (page == null) {
                break;
            }

            for (Branch branch : page.getValues()) {
                callback.onBranch(branch);
            }

            pageRequest = page.getNextPageRequest();
            if (pageRequest == null) { //This null check is the same as checking page.getIsLastPage()
                break;
            }
        }
    }
}
