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

import com.atlassian.bitbucket.mesh.git.GitProcessCompletionHandler;
import com.atlassian.bitbucket.mesh.git.exception.CommitNotFoundException;
import com.atlassian.bitbucket.mesh.git.exception.InvalidTreeishException;
import com.atlassian.bitbucket.mesh.git.exception.PathNotFoundException;
import com.atlassian.bitbucket.mesh.process.ProcessCompletionHandler;
import com.atlassian.bitbucket.mesh.process.ProcessSummary;
import com.atlassian.bitbucket.mesh.process.handler.AbstractLineStdioHandler;
import com.atlassian.bitbucket.mesh.process.handler.LineDecoder;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BlobLsTreeStdioHandler extends AbstractLineStdioHandler<List<String>> implements ProcessCompletionHandler {

    //Only match blobs (files)
    private static final Pattern PATTERN = Pattern.compile("\\d+ blob [0-9a-fA-F]{40}\\t(.*)");
    private static final String NOT_TREE_PREFIX = "fatal: not a tree object";

    private final String commitId;
    private final List<String> files = new ArrayList<>();
    private final String path;

    public BlobLsTreeStdioHandler(String commitId, String path) {
        super(StandardCharsets.UTF_8, LineDecoder.Mode.NULL);
        this.commitId = commitId;
        this.path = path;
    }

    @Override
    public List<String> getResult() {
        return files;
    }

    @Override
    public void onComplete(@Nonnull ProcessSummary summary) {
        new BlobLsTreeCompletionHandler(commitId, path).onComplete(summary);
    }

    @Override
    protected boolean onStdout(@Nonnull String line, boolean truncated) {
        Matcher matcher = PATTERN.matcher(line);
        if (matcher.matches()) {
            String file = matcher.group(1);

            files.add(file);
        }

        return true;
    }

    private static class BlobLsTreeCompletionHandler extends GitProcessCompletionHandler {

        private final String commitId;
        private final String path;

        BlobLsTreeCompletionHandler(String commitId, String path) {
            this.commitId = commitId;
            this.path = path;
        }

        @Override
        protected void evaluateStderr(@Nonnull ProcessSummary summary, @Nonnull String stderr) {
            //This replaces the handling for this pattern in the GitProcessCompletionHandler. That throws an
            //ObjectNotFoundException and we want a CommitNotFoundException
            Matcher matcher = PATTERN_NOT_FOUND.matcher(stderr);
            if (matcher.matches()) {
                String commitId = matcher.group(1);
                String path = matcher.group(2);
                if (StringUtils.isEmpty(path)) {
                    throw new CommitNotFoundException(commitId);
                }

                throw new PathNotFoundException(commitId, path);
            }
            if (stderr.startsWith(NOT_TREE_PREFIX)) {
                throw new InvalidTreeishException(commitId + ":" + path);
            }

            super.evaluateStderr(summary, stderr);
        }
    }
}
