package com.atlassian.bitbucket.mesh;

import com.atlassian.bitbucket.mesh.client.MeshClient;
import com.atlassian.bitbucket.mesh.git.GitPackFile;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.git.exception.CommitNotFoundException;
import com.atlassian.bitbucket.mesh.management.NodeManager;
import com.atlassian.bitbucket.mesh.network.MeshManager;
import com.atlassian.bitbucket.mesh.network.MeshNode;
import com.atlassian.bitbucket.mesh.repair.MissingObjectsFetcher;
import com.atlassian.bitbucket.mesh.repository.ManagedRepository;
import com.atlassian.bitbucket.mesh.test.annotation.DirtiesRepo;
import com.atlassian.bitbucket.mesh.test.annotation.Repo;
import org.junit.Before;
import org.junit.Test;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.Assert.*;

public class MissingObjectFetcherTest extends AbstractWiredTest {

    @Resource
    private GitProcessBuilderFactory builderFactory;
    @Resource
    private MeshClient meshClient;
    @Resource
    private MeshManager meshManager;
    @Resource
    private NodeManager nodeManager;
    private MeshNode replica;
    @Repo
    private ManagedRepository repository;
    @Resource
    private TestHelper testHelper;

    @Before
    public void setUp() {
        replica = meshManager.getNodes().stream()
                .filter(MeshNode::isRemote)
                .findFirst()
                .orElse(null);

        assertNotNull("No remote cluster node is configured", replica);
    }

    @DirtiesRepo
    @Test
    public void testMaybeFetch() throws IOException {
        //Create a new commit on replica
        String commitId = testHelper.createCommit(replica, repository.getId());

        try (MissingObjectsFetcher fetcher = new MissingObjectsFetcher(
                builderFactory, meshClient, repository, replica)) {
            fetcher.includeIfMissing(commitId);
            GitPackFile packFile = fetcher.maybeFetch();
            assertNotNull("Pack file was not created", packFile);
            Path packFilePath = packFile.getPath();
            assertTrue("Pack file not found: " + packFilePath, Files.isRegularFile(packFilePath));
            Path keepFile = getKeepFile(packFile);
            assertTrue("Keep file not found: " + keepFile, Files.isRegularFile(keepFile));
            packFile.close();
            assertFalse("Keep file was not removed on close", Files.isRegularFile(keepFile));
        }
    }

    @Test
    public void testMaybeFetchThrowsIfObjectUnknown() {
        try (MissingObjectsFetcher fetcher = new MissingObjectsFetcher(
                builderFactory, meshClient, repository, replica)) {
            fetcher.includeIfMissing("abcdef0123abcdef0123abcdef0123abcdef0123");
            assertThrows(CommitNotFoundException.class, fetcher::maybeFetch);
        }
    }

    private static Path getKeepFile(GitPackFile packFile) {
        Path path = packFile.getPath();
        String filename = path.getFileName().toString();
        return path.resolveSibling(filename.substring(0, filename.length() - 5) + ".keep");
    }
}
