package com.atlassian.bitbucket.mesh.git.submodule;

import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.git.builder.catfile.SubmoduleCatFileStdioHandler;
import com.atlassian.bitbucket.mesh.git.exception.CommitNotFoundException;
import com.atlassian.bitbucket.mesh.git.exception.PathNotFoundException;
import com.atlassian.bitbucket.mesh.repository.Repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;

import static com.atlassian.bitbucket.mesh.git.GitConstants.PATH_GITMODULES;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang3.StringUtils.appendIfMissing;
import static org.apache.commons.lang3.StringUtils.isEmpty;

/**
 * An implementation of {@link Submodules} which defers reading {@code .gitmodules} until the first submodule
 * is requested. Since most repositories don't use submodules, this avoids unnecessary overhead.
 */
class LazySubmodules implements Submodules {

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

    private final String basePath;
    private final GitProcessBuilderFactory builderFactory;
    private final String commitId;
    private final Repository repository;

    private Map<String, SubmoduleConfig> configByPath;

    LazySubmodules(@Nonnull GitProcessBuilderFactory builderFactory, @Nonnull Repository repository,
                   @Nonnull String commitId, String basePath) {
        this.basePath = isEmpty(basePath) ? "" : appendIfMissing(basePath, "/");
        this.builderFactory = requireNonNull(builderFactory, "builderFactory");
        this.commitId = requireNonNull(commitId, "commitId");
        this.repository = requireNonNull(repository, "repository");
    }

    @Override
    public Submodule get(@Nonnull String path, @Nonnull String contentId) {
        if (configByPath == null) {
            try {
                configByPath = builderFactory.builder(repository).catFile()
                        .pretty()
                        .object(commitId, PATH_GITMODULES)
                        .build(new SubmoduleCatFileStdioHandler(repository))
                        .run();
            } catch (CommitNotFoundException | PathNotFoundException ignored) {
                log.info("{}: No submodules are configured for {}", repository, commitId);
                configByPath = Collections.emptyMap();
            }
        }

        SubmoduleConfig config = configByPath.get(basePath + path);
        if (config == null) {
            return null;
        }

        return new Submodule(path, contentId, config);
    }
}
