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

import com.atlassian.bitbucket.mesh.git.builder.push.PushProgressStateMachine.ProgressStep;

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

public class PushProgressHelper {

    private static final Pattern PERCENTAGE_PATTERN = Pattern.compile("^\\s*(\\d+)%");

    private final BiConsumer<Integer, String> onProgress;
    private final PushProgressStateMachine stateMachine;

    public PushProgressHelper(@Nonnull PushProgressStateMachine stateMachine,
                              @Nonnull BiConsumer<Integer, String> onProgress) {
        this.onProgress = onProgress;
        this.stateMachine = stateMachine;
    }

    /**
     * Processes a line from a Git command output and calls the progress consumer if the progress relates to the passed
     * in {@link PushProgressStateMachine state machine}.
     * <p>
     * Note: this method will return {@code true} for any line that looks like progress output, even if it did not result
     * in a callback being called.
     *
     * @param line a line from a Git process output
     * @return {@code true} when the line looks like a progress output line, {@code false} when it does not
     */
    public boolean processLine(@Nonnull String line) {
        // If for some reason Git thinks we're attached to a TTY, strip the ANSI escape sequence to clear the line.
        if (line.startsWith("\u001B[K")) {
            line = line.substring("\u001B[K".length());
        }
        line = line.startsWith("remote: ") ? line.substring("remote: ".length()) : line;
        line = line.trim();
        for (ProgressStep state : ProgressStep.values()) {
            if (line.startsWith(state.getLabel())) {
                processProgressLine(line, state);
                return true;
            }
        }
        return false;
    }

    private void processProgressLine(String line, ProgressStep progressStep) {
        Matcher matcher = PERCENTAGE_PATTERN.matcher(line.substring(progressStep.getLabel().length() + 1));
        float currentPercentage;
        if (matcher.find()) {
            currentPercentage = Integer.parseInt(matcher.group(1)) / 100.0f;
        } else {
            currentPercentage = 0;
        }

        stateMachine.getTotalPercentage(progressStep, currentPercentage).ifPresent(totalPercentage -> {
            onProgress.accept((int) Math.floor(totalPercentage * 100), line);
        });
    }
}
