package com.atlassian.stash.internal.home;

import com.atlassian.bitbucket.util.FileUtils;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@RunWith(MockitoJUnitRunner.class)
@Ignore
public abstract class AbstractFileMoverTest {
    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Test
    public void testMoveEmpty() throws IOException {
        File rootDir = folder.newFolder("move-empty");
        File sourceDir = FileUtils.mkdir(rootDir, "src");
        File targetDir = new File(rootDir, "dst");

        getFileMover().move(sourceDir, targetDir);

        assertFalse(sourceDir.exists());
        assertTrue(targetDir.exists());
    }

    @Test
    public void testMoveFiles() throws IOException {
        File rootDir = folder.newFolder("move-files");
        File sourceDir = FileUtils.mkdir(rootDir, "src");
        File targetDir = new File(rootDir, "dst");

        TestFiles createdFiles = createFiles("move-file", sourceDir, targetDir);

        getFileMover().move(sourceDir, targetDir);

        assertFalse(sourceDir.exists());
        assertTrue(targetDir.exists());

        assertTestFiles(createdFiles);
    }

    @Test
    public void testMoveDirs() throws IOException {
        File rootDir = folder.newFolder("move-dirs");
        File sourceDir = FileUtils.mkdir(rootDir, "src");
        File targetDir = new File(rootDir, "dst");

        List<File> sourceFiles = new ArrayList<>();
        List<File> targetFiles = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            String fileName = i + "-dir";
            File sourceFile = new File(sourceDir, fileName);
            sourceFiles.add(sourceFile);
            targetFiles.add(new File(targetDir, fileName));
            sourceFile.mkdir();
        }

        getFileMover().move(sourceDir, targetDir);

        assertFalse(sourceDir.exists());
        assertTrue(targetDir.exists());
        for (int i = 0; i < 10; i++) {
            File targetFile = targetFiles.get(i);
            assertTrue(targetFile.exists());
        }
    }

    @Test
    public void testMoveAll() throws IOException {
        File rootDir = folder.newFolder("move-all");
        File sourceDir = FileUtils.mkdir(rootDir, "src");
        File targetDir = new File(rootDir, "dst");

        TestFiles rootFiles = createFiles("move-root", sourceDir, targetDir);
        List<TestFiles> subFiles = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            String fileName = "all-" + i + "-dir";
            File sourceFile = new File(sourceDir, fileName);
            sourceFile.mkdir();

            File targetFile = new File(targetDir, fileName);
            subFiles.add(createFiles("all-sub-" + i, sourceFile, targetFile));
        }

        getFileMover().move(sourceDir, targetDir);

        assertFalse(sourceDir.exists());
        assertTrue(targetDir.exists());

        assertTestFiles(rootFiles);
        for (TestFiles testFile : subFiles) {
            assertTestFiles(testFile);
        }
    }

    private TestFiles createFiles(String prefix, File sourceDir, File targetDir) throws IOException {
        TestFiles testFiles = new TestFiles();

        for (int i = 0; i < 10; i++) {
            String fileName = prefix + "-" + i + ".txt";
            File sourceFile = new File(sourceDir, fileName);
            testFiles.sourceFiles.add(sourceFile);
            testFiles.targetFiles.add(new File(targetDir, fileName));

            try (FileWriter writer = new FileWriter(sourceFile)) {
                String line = prefix + ":" + i + ":" + prefix;
                testFiles.content.add(line);
                writer.write(line);
            }
        }

        return testFiles;
    }

    private void assertTestFiles(TestFiles testFiles) throws IOException {
        for (int i = 0; i < 10; i++) {
            assertFalse(testFiles.sourceFiles.get(i).exists());

            File targetFile = testFiles.targetFiles.get(i);
            assertTrue(targetFile.exists());

            try (BufferedReader reader = new BufferedReader(new FileReader(targetFile))) {
                assertEquals(testFiles.content.get(i), reader.readLine());
            }
        }
    }

    private static class TestFiles {
        private final List<File> sourceFiles = new ArrayList<>();
        private final List<File> targetFiles = new ArrayList<>();
        private final List<String> content = new ArrayList<>();
    }

    protected abstract FileMover getFileMover();
}
