package com.atlassian.bitbucket.internal.branch.automerge;

import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.internal.branch.automerge.result.MergeFailedReason;
import com.atlassian.bitbucket.internal.branch.automerge.result.MergeResult;
import com.atlassian.bitbucket.internal.branch.automerge.result.MergeStopped;
import com.atlassian.bitbucket.internal.branch.automerge.result.MergeSuccess;
import com.atlassian.bitbucket.repository.Branch;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.Command;
import com.atlassian.bitbucket.scm.MergeCommandParameters;
import com.atlassian.bitbucket.scm.ScmService;
import com.atlassian.bitbucket.user.ApplicationUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;

import java.text.MessageFormat;

import static java.util.Objects.requireNonNull;

/**
 * Actually handles the merge itself, catching the errors and returning the appropriate result
 */
@Order(3)
public class MergeAction implements BranchProcessor {

    private static final Logger log = LoggerFactory.getLogger(MergeAction.class);

    private final AuthenticationContext authenticationContext;
    private final AutoMergeConfig config;
    private final ScmService scmService;

    public MergeAction(AuthenticationContext authenticationContext, AutoMergeConfig config, ScmService scmService) {
        this.authenticationContext = authenticationContext;
        this.config = config;
        this.scmService = scmService;
    }

    @Override
    public MergeResult process(MergeInstruction mergeInstruction) {
        Repository repository = mergeInstruction.getRepository();
        Branch source = mergeInstruction.getSource();
        Branch destination = mergeInstruction.getDestination();

        try {
            log.debug("Attempting to auto-merge {} to {}", source.getDisplayId(), destination.getDisplayId());

            ApplicationUser currentUser = requireNonNull(authenticationContext.getCurrentUser(), "current user required for automatic merge");
            long timeout = config.getTimeout();

            Command<Branch> command = scmService.getExtendedCommandFactory(repository)
                    .merge(new MergeCommandParameters.Builder()
                            .author(currentUser)
                            .fromBranch(source.getId())
                            .message(MessageFormat.format("Automatic merge from {0} -> {1}", source.getDisplayId(), destination.getDisplayId()))
                            .toBranch(destination.getId())
                            .build());
            command.setExecutionTimeout(timeout);
            command.setIdleTimeout(timeout);

            return new MergeSuccess(command.call());
        } catch (Exception e) {
            log.debug("Auto-merge {} to {} failed with exception", source.getDisplayId(), destination.getDisplayId(), e);
            return new MergeStopped(new MergeFailedReason());
        }
    }
}
