package com.atlassian.bitbucket.mesh;

import com.atlassian.bitbucket.mesh.app.BuildInfo;
import com.atlassian.bitbucket.mesh.com.atlassian.bitbucket.mesh.SimpleTransactionManager;
import com.atlassian.bitbucket.mesh.config.ApplicationConfig;
import com.atlassian.bitbucket.mesh.execution.ExecutionManager;
import com.atlassian.bitbucket.mesh.git.GitQuarantineRegistry;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.git.hook.*;
import com.atlassian.bitbucket.mesh.git.hook.script.DefaultHookScriptManager;
import com.atlassian.bitbucket.mesh.git.hook.script.HookScriptCommandLineFactory;
import com.atlassian.bitbucket.mesh.git.hook.script.HookScriptManager;
import com.atlassian.bitbucket.mesh.io.MoreFiles;
import com.atlassian.bitbucket.mesh.layout.DestroyableStorageLayout;
import com.atlassian.bitbucket.mesh.layout.HomeSubdirectoryResolver;
import com.atlassian.bitbucket.mesh.layout.StorageLayout;
import com.atlassian.bitbucket.mesh.process.ProcessCreator;
import com.atlassian.bitbucket.mesh.repository.*;
import com.atlassian.bitbucket.mesh.test.ExecutionContextRule;
import com.atlassian.bitbucket.mesh.test.ExpectedEvents;
import com.atlassian.bitbucket.mesh.test.context.MapRepositoryCache;
import com.atlassian.bitbucket.mesh.test.context.RepositoryCache;
import com.atlassian.bitbucket.mesh.util.Version;
import com.google.common.collect.ImmutableList;
import org.springframework.context.annotation.*;
import org.springframework.transaction.PlatformTransactionManager;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@PropertySources({
        @PropertySource("classpath:application-private.properties"),
        @PropertySource("classpath:application-public.properties"),
        @PropertySource("classpath:application-test.properties")
})
@ImportResource("classpath:mesh-listeners.xml") //See comment in file for why this is XML
public class MeshTestWiring {

    @Bean //This overrides the MeshCoreWiring version, which also disables the home directory property checks
    public ApplicationDirs applicationDirs() throws IOException {
        Path home = Files.createTempDirectory("home").toAbsolutePath();
        Path sharedHome = MoreFiles.mkdir(home, "shared");

        //Set a system property for the home directory to allow referring to it from properties
        System.setProperty("mesh.home", home.toString());

        return new ApplicationDirs(home, sharedHome, ImmutableList.of(home.resolve("store")));
    }

    @Bean
    public ExecutionContextRule executionContextRule(ExecutionManager executionManager) {
        return new ExecutionContextRule(executionManager);
    }

    @Bean
    public ExpectedEvents expectedEvents() {
        return new ExpectedEvents();
    }

    @Bean(destroyMethod = "shutdown", initMethod = "startup")
    public DefaultGitHookService gitHookService(ApplicationConfig config, ExecutionManager executionManager,
                                                GitHookThreadPoolExecutor executor, List<GitHookHandler> handlers,
                                                RepositoryManager repositoryManager, StorageLayout storageLayout) {
        return new ConfigurableGitHookService(config.getGit().getHooks(), executionManager,
                executor, handlers, repositoryManager, storageLayout.getTempDir());
    }

    @Bean
    public HookScriptManager hookScriptManager(GitProcessBuilderFactory builderFactory,
                                               HookScriptCommandLineFactory commandLineFactory,
                                               ApplicationConfig config, ProcessCreator processCreator,
                                               GitQuarantineRegistry quarantineRegistry, StorageLayout storageLayout) {
        return new DefaultHookScriptManager(builderFactory, commandLineFactory, config.getGit().getHookScripts(),
                processCreator, quarantineRegistry, storageLayout, false);
    }

    @Bean
    public ManagedDataStore managedDataStore(ApplicationDirs applicationDirs, BuildInfo buildInfo,
                                             @Lazy GitHookService hookService) {
        return new ManagedDataStore(new Version(buildInfo.getBuildVersion()), hookService,
                applicationDirs.getDataDirs());
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager() {
        return new SimpleTransactionManager();
    }

    @Bean
    public RepositoryAttributeDao repositoryAttributeDao() {
        return new SimpleRepositoryAttributeDao();
    }

    @Bean
    public RepositoryCache repositoryCache() {
        return new MapRepositoryCache();
    }

    @Bean(destroyMethod = "destroy")
    public DestroyableStorageLayout storageLayout(ApplicationDirs applicationDirs,
                                                  HomeSubdirectoryResolver homeSubdirectoryResolver) {
        return new DestroyableStorageLayout(applicationDirs, homeSubdirectoryResolver);
    }

    @Bean
    public WorkTreeStateDao workTreeStateDao() {
        return new SimpleWorkTreeStateDao();
    }
}
