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

import com.atlassian.bitbucket.mesh.git.GitChangeType;
import com.atlassian.bitbucket.mesh.git.GitNodeType;
import com.atlassian.bitbucket.mesh.git.batch.BatchChange;
import com.atlassian.bitbucket.mesh.git.batch.BatchChangeType;
import com.atlassian.bitbucket.mesh.git.content.Change;
import com.atlassian.bitbucket.mesh.io.NullTerminatedWriter;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Writer;

import static java.util.Objects.requireNonNull;

public class FileWritingDiffTreeStdioHandler extends AbstractDiffTreeStdioHandler<Void> {

    private static final Long UNKNOWN_SIZE = -1L;

    private final NullTerminatedWriter writer;

    public FileWritingDiffTreeStdioHandler(@Nonnull Writer writer) {
        this.writer = new NullTerminatedWriter(requireNonNull(writer, "writer"));
    }

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

    @Override
    protected boolean onStdout(@Nonnull String line, boolean truncated) {
        if (line.isEmpty()) {
            //git diff-tree outputs a blank line between the commit hash and the diff tree, which we ignore
            return true;
        }

        Change change = parseChange(line);
        if (change.getNodeType() != GitNodeType.FILE) {
            // Recursive diff-tree already results in no DIRECTORY entries, but we also want to skip SUBMODULE.
            return true;
        }

        try {
            String path = change.getPath();
            String contentId = change.getContentId();
            GitChangeType type = change.getType();
            switch (type) {
                case ADD:
                    BatchChange.write(path, BatchChangeType.ADD, contentId, UNKNOWN_SIZE, writer);
                    break;
                case TYPE:
                case MODIFY:
                    BatchChange.write(path, BatchChangeType.MODIFY, contentId, UNKNOWN_SIZE, writer);
                    break;
                case DELETE:
                    BatchChange.write(path, BatchChangeType.DELETE, contentId, UNKNOWN_SIZE, writer);
                    break;
                default:
                    throw new IllegalStateException("Unexpected change type " + type + " for file with path: " + path);
            }
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }

        return true;
    }
}
