package com.atlassian.bitbucket.mesh.layout;

import com.atlassian.bitbucket.mesh.ApplicationDirs;
import com.atlassian.bitbucket.mesh.io.MoreFiles;

import javax.annotation.Nonnull;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public class SimpleStorageLayout implements StorageLayout {

    private final Path binDir;
    private final Path cacheDir;
    private final Path configDir;
    private final Path homeDir;
    private final Path hooksScriptsDir;
    private final Path logDir;
    private final Path scriptsDir;
    private final Path tempDir;

    public SimpleStorageLayout(ApplicationDirs applicationDirs, HomeSubdirectoryResolver resolver) {
        homeDir = MoreFiles.mkdir(applicationDirs.getHomeDir());

        binDir = MoreFiles.mkdir(homeDir, "bin");
        cacheDir = resolver.resolve(homeDir, "caches");
        configDir = MoreFiles.mkdir(homeDir, "config");
        hooksScriptsDir = findHookScriptsDir(applicationDirs);
        logDir = MoreFiles.mkdir(homeDir, "log");
        scriptsDir = MoreFiles.mkdir(binDir, "git-scripts");
        tempDir = resolver.resolve(homeDir, "tmp");
    }

    @Nonnull
    @Override
    public Path getBinDir() {
        return binDir;
    }

    @Nonnull
    @Override
    public Path getCacheDir() {
        return cacheDir;
    }

    @Nonnull
    @Override
    public Path getConfigDir() {
        return configDir;
    }

    @Nonnull
    @Override
    public Path getConfigFile() {
        return homeDir.resolve(MESH_PROPERTIES);
    }

    @Nonnull
    @Override
    public Path getHomeDir() {
        return homeDir;
    }

    @Nonnull
    @Override
    public Path getHookScriptsDir() {
        return hooksScriptsDir;
    }

    @Nonnull
    @Override
    public Path getLogDir() {
        return logDir;
    }

    @Nonnull
    @Override
    public Path getNodeConfigFile() {
        return homeDir.resolve(MESH_NODE_PROPERTIES);
    }

    @Nonnull
    @Override
    public Path getScriptsDir() {
        return scriptsDir;
    }

    @Nonnull
    @Override
    public Path getTempDir() {
        return tempDir;
    }

    @Nonnull
    private static Path findHookScriptsDir(ApplicationDirs applicationDirs) {
        Path sharedHome = applicationDirs.getSharedHome();
        if (sharedHome != null) {
            //BBS shared-home hook-scripts directory when running as sidecar
            return sharedHome.resolve("config").resolve("hook-scripts");
        }

        //When checking for an existing hook-scripts directory, we _prefer_ dataDirs, but we also need to
        //check the homeDir in case a previous run without any data stores wrote the hook scripts there
        List<Path> candidates = new ArrayList<>(applicationDirs.getDataDirs());
        candidates.add(applicationDirs.getHomeDir()); //This ensures candidates is never empty

        return candidates.stream()
                //Look for an existing hook-scripts directory
                .map(candidate -> candidate.resolve("hook-scripts"))
                .filter(Files::isDirectory)
                .findFirst()
                //If no hook-scripts dir was found, store the hook-scripts on the first data store or, if
                //there are no data stores, in the home directory
                .orElseGet(() -> candidates.get(0).resolve("hook-scripts"));
    }
}
