package com.atlassian.stash.internal.idx.upgrade;

import com.atlassian.stash.internal.ApplicationSettings;
import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.File;
import java.util.Set;

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class MoveSnapshotDirUpgradeTaskTest {
    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    @Mock
    private ApplicationSettings applicationSettings;

    private File cacheDir;
    private File configDir;
    private File dataDir;

    @Before
    public void setUp() throws Exception {
        cacheDir = temporaryFolder.newFolder();
        configDir = temporaryFolder.newFolder();
        dataDir = temporaryFolder.newFolder();

        when(applicationSettings.getDataDir()).thenReturn(dataDir);
        when(applicationSettings.getCacheDir()).thenReturn(cacheDir);
        when(applicationSettings.getConfigDir()).thenReturn(configDir);
    }

    @Test
    public void testMovingSnapshotsDir() throws Exception {
        testMovingSnapshotsDirWith(new MoveSnapshotDirUpgradeTask(applicationSettings));
    }

    @Test
    public void testMovingSnapshotsDirFileByFile() throws Exception {
        testMovingSnapshotsDirWith(new MoveSnapshotDirUpgradeTask(applicationSettings) {
            @Override
            boolean renameTo(File snapshotDir, File previousSnapshotDir) {
                //Force moving each file and directory individually
                return false;
            }
        });
    }

    @Test
    public void testMovingSnapshotsDirAlreadyDone() throws Exception {
        File taskMarker = new File(configDir, "upgrades/core-idx-snapshots");
        assertTrue(taskMarker.getParentFile().mkdirs());
        assertTrue(taskMarker.createNewFile());

        File cachesSnapshotDir = new File(cacheDir, "idx-snapshots");
        File caches22SnapshotDir = new File(cachesSnapshotDir, "22");
        assertTrue(caches22SnapshotDir.mkdirs());
        File dataSnapshotDir = new File(dataDir, "snapshots/22");

        new MoveSnapshotDirUpgradeTask(applicationSettings).afterPropertiesSet();

        assertTrue(caches22SnapshotDir.exists());
        assertFalse(dataSnapshotDir.exists());
    }

    @Test
    public void testNoSnapshotsDir() throws Exception {
        File dataSnapshotDir = new File(dataDir, "snapshots");

        new MoveSnapshotDirUpgradeTask(applicationSettings).afterPropertiesSet();

        assertTrue(dataSnapshotDir.exists());
    }

    @Test
    public void testNewSnapshotsDirAlreadyExists() throws Exception {
        File cachesSnapshotDir = new File(cacheDir, "idx-snapshots");
        File caches22SnapshotDir = new File(cachesSnapshotDir, "22");
        assertTrue(caches22SnapshotDir.mkdirs());

        File dataSnapshotDir = new File(dataDir, "snapshots");
        assertTrue(dataSnapshotDir.mkdirs());

        File data22SnapshotDir = new File(dataSnapshotDir, "22");

        new MoveSnapshotDirUpgradeTask(applicationSettings).afterPropertiesSet();

        assertFalse(data22SnapshotDir.exists());
        assertFalse(cachesSnapshotDir.exists());
    }

    private void testMovingSnapshotsDirWith(MoveSnapshotDirUpgradeTask upgradeTask) throws Exception {
        File cachesSnapshotDir = new File(cacheDir, "idx-snapshots");
        File caches22SnapshotDir = new File(cachesSnapshotDir, "22");
        assertTrue(caches22SnapshotDir.mkdirs());

        // create a bunch of snapshot files on disk
        for (int i = 1001; i < 1005; ++i) {
            assertTrue(new File(caches22SnapshotDir, Integer.toString(i)).createNewFile());
        }

        //Cause them to be migrated from caches/ to data/
        upgradeTask.afterPropertiesSet();

        assertFalse(caches22SnapshotDir.exists());
        assertFalse(caches22SnapshotDir.getParentFile().exists());

        File data22SnapshotDir = new File(dataDir, "snapshots/22");
        Set<File> snapshotFiles = Sets.newHashSet(data22SnapshotDir.listFiles());
        assertEquals(Sets.newHashSet(new File(data22SnapshotDir, "1001"), new File(data22SnapshotDir, "1002"),
                new File(data22SnapshotDir, "1003"), new File(data22SnapshotDir, "1004")), snapshotFiles);

        assertFalse(caches22SnapshotDir.exists());
        assertFalse(cachesSnapshotDir.exists());

        assertTrue(new File(configDir, "upgrades/core-idx-snapshots").exists());
    }
}
