package com.atlassian.stash.internal.scm.git.command.foreachref;

import com.atlassian.bitbucket.io.LineReader;
import com.atlassian.bitbucket.io.LineReaderOutputHandler;
import com.atlassian.bitbucket.repository.*;
import com.atlassian.bitbucket.scm.CommandResult;
import com.atlassian.bitbucket.scm.CommandSummary;
import com.atlassian.bitbucket.scm.CommandSummaryHandler;
import com.atlassian.bitbucket.scm.git.GitRefPattern;
import com.atlassian.utils.process.ProcessException;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class AllRefsForEachRefOutputHandler
        extends LineReaderOutputHandler
        implements CommandSummaryHandler, ForEachRefOutputHandler<Void> {

    public static final RefContext EMPTY_CONTEXT = new RefContext.Builder().build();
    public static final String FORMAT = ForEachRefUtils.normalize("%(refname)|%(objectname)|%(*objectname)");

    private final RefCallback callback;
    private final String defaultBranch;

    private int added;

    public AllRefsForEachRefOutputHandler(RefCallback callback, String defaultBranch) {
        super(StandardCharsets.UTF_8);

        this.callback = callback;
        this.defaultBranch = defaultBranch;
    }

    @Nonnull
    @Override
    public String getFormat() {
        return FORMAT;
    }

    @Override
    public Void getOutput() {
        return null;
    }

    @Override
    public void onComplete(@Nonnull CommandSummary summary) throws ProcessException {
        try {
            if (added > 0) {
                callback.onEnd(new RefSummary.Builder(summary).build());
            } else if (summary.getResult() == CommandResult.SUCCEEDED) {
                callback.onStart(EMPTY_CONTEXT);
                callback.onEnd(new RefSummary.Builder(summary).build());
            }
        } catch (IOException e) {
            throw new ProcessException(e);
        }
    }

    @Override
    protected void processReader(LineReader reader) throws IOException {
        String line;
        while ((line = resetWatchdogAndReadLine(reader)) != null) {
            String[] pieces = line.split(ForEachRefUtils.SEPARATOR_CHAR);
            if (pieces.length < 2) {
                continue;
            }

            Ref ref;
            if (pieces[0].startsWith(GitRefPattern.TAGS.getPath())) {
                SimpleTag.Builder builder = new SimpleTag.Builder()
                        .displayId(GitRefPattern.TAGS.unqualify(pieces[0]))
                        .id(pieces[0]);
                if (pieces.length == 3) {
                    //Annotated tag
                    builder.hash(pieces[1]).latestCommit(pieces[2]).build();
                } else {
                    //Lightweight tag
                    builder.latestCommit(pieces[1]).build();
                }
                ref = builder.build();
            } else {
                ref = new SimpleBranch.Builder()
                        .displayId(GitRefPattern.HEADS.unqualify(pieces[0]))
                        .id(pieces[0])
                        .isDefault(defaultBranch.equals(pieces[0]))
                        .latestCommit(pieces[1])
                        .build();
            }

            if (added++ == 0) {
                callback.onStart(EMPTY_CONTEXT);
            }

            boolean shouldContinue = callback.onRef(ref);
            if (!shouldContinue) {
                break;
            }
        }
    }
}
