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

import com.atlassian.bitbucket.mesh.git.GitProcessCompletionHandler;
import com.atlassian.bitbucket.mesh.git.exception.InvalidMergeException;
import com.atlassian.bitbucket.mesh.git.exception.NonFastForwardMergeException;
import com.atlassian.bitbucket.mesh.process.ProcessSummary;
import com.atlassian.bitbucket.mesh.rpc.v1.RpcInvalidMerge;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MergeCompletionHandler extends GitProcessCompletionHandler {

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

    private static final String MESSAGE_NON_FAST_FORWARD = "fatal: Not possible to fast-forward, aborting.";
    private static final String MESSAGE_UNRELATED_HISTORIES = "fatal: refusing to merge unrelated histories";
    private static final Pattern PATTERN_ADDINFO_CACHE_FAILED = Pattern.compile("error: addinfo_cache failed for path '(.+)'$");

    @Override
    protected void evaluateStderr(@Nonnull ProcessSummary summary, @Nonnull String stderr) {
        String cleanedStderr = ADVICE_PATTERN.matcher(stderr).replaceAll("");
        if (MESSAGE_NON_FAST_FORWARD.equals(cleanedStderr)) {
            throw new NonFastForwardMergeException();
        }
        if (MESSAGE_UNRELATED_HISTORIES.equals(cleanedStderr)) {
            throw new InvalidMergeException(RpcInvalidMerge.Reason.UNRELATED);
        }
        super.evaluateStderr(summary, stderr);
    }

    @Override
    protected boolean isError(@Nonnull String line) {
        if (line.startsWith("error")) {
            Matcher matcher = PATTERN_ADDINFO_CACHE_FAILED.matcher(line);
            if (matcher.matches()) {
                //merge-recursive attempts to create cache entries for files that are not involved in the merge,
                //in some versions of git. Because the file for which the cache entry is being created does not
                //exist on disk, that attempt fails and git logs this error output. However, the actual merge is
                //not affected by this, since it only happens for paths _not_ modified in the merge.
                if (log.isTraceEnabled()) {
                    log.trace("BUGCHECK: addinfo_cache failure for {} is being ignored", matcher.group(1));
                }
                return false;
            } else {
                return true;
            }
        }
        return super.isError(line);
    }
}
