const fs = require("fs-extra");
const path = require("path");
const tmpDir = process.platform === "win32" ? process.env.TEMP : "/tmp";

function macros() {
  const testDir = path.join(tmpDir, "sulu-test");
  const testSuluFolder = "sulu";
  const testSuluDir = path.join(testDir, testSuluFolder);
  const pluginTestsFolders = ["plugin-1", "plugin-2"];
  const testPluginsDirsList = pluginTestsFolders.map((p) =>
    path.join(testDir, p)
  );
  const testPluginsDirsString = testPluginsDirsList.reduce(
    (agg, curr) => `${agg}${curr},`,
    ""
  );
  const testWriteResultDir = path.join(testDir, "dist1");
  const mockPluginManifest = {
    pattern: ".(js|jsx|ts|tsx)$",
    excludePattern: "includeExcludePatternMatch.js",
    integrate_package_file_dependencies: true,
    integrate_package_file_dev_dependencies: true,
  };
  const mockPluginMatchContents = pluginTestsFolders.map(
    (x) => `Mock contents for ${x} pattern match file`
  );
  const mockPluginOverridenFileContents = pluginTestsFolders.map(
    (x) => `Mock contents for ${x} that overrides core sulu file of same name`
  );

  return {
    testDir,
    testSuluDir,
    pluginTestsFolders,
    testPluginsDirsList,
    testPluginsDirsString,
    testWriteResultDir,
    mockPluginManifest,
    mockPluginMatchContents,
    mockPluginOverridenFileContents,
    mockSuluIndexContents: "mock sulu index.js contents",
    mockSuluOverridenFileContents:
      "mock sulu file that will be overriden by plugin contents",
    mockSuluPackageJsonContents: {
      name: "test-package-json",
      version: "1.0.0",
      dependencies: {
        "mock-dep-1": "1.0.0",
        "mock-dep-2": "2.0.0",
      },
      devDependencies: {
        "mock-dev-dep-1": "1.0.0",
        "mock-dev-dep-2": "2.0.0",
      },
    },
    mockPluginPackageJsonContents: {
      name: "test-plugin-package-json",
      version: "1.0.0",
      dependencies: {
        "pl-mock-dep-3": "3.0.0",
        "pl-mock-dep-4": "4.0.0",
      },
      devDependencies: {
        "pl-mock-dev-dep-3": "1.0.0",
        "pl-mock-dev-dep-4": "2.0.0",
      },
    },
    log: () => 0,
  };
}

// to prevent any mutations by cross-files.
module.exports = {
  macros,
  beforeEachTest: () => {
    const {
      testDir,
      testSuluDir,
      testWriteResultDir,
      testPluginsDirsList,
      mockPluginManifest,
      mockSuluIndexContents,
      mockSuluOverridenFileContents,
      mockPluginOverridenFileContents,
      mockSuluPackageJsonContents,
      mockPluginPackageJsonContents,
      mockPluginMatchContents,
    } = macros();
    // empty root directory
    fs.emptyDirSync(testDir);

    // empty dir for results
    fs.emptyDirSync(testWriteResultDir);

    // ---- sulu mock ----
    // empty sulu directory
    fs.emptyDirSync(testSuluDir);
    // mock file in sulu directory
    fs.writeFileSync(path.join(testSuluDir, "index.js"), mockSuluIndexContents);
    // empty nested directory in sulu
    fs.emptyDirSync(path.join(testSuluDir, "src"));
    // mock file in nested directory in sulu
    fs.writeFileSync(
      path.join(testSuluDir, "src", "index.js"),
      mockSuluIndexContents
    );
    // mock file in sulu directory that will be overriden by plugin
    fs.writeFileSync(
      path.join(testSuluDir, "src", "overriden-file.js"),
      mockSuluOverridenFileContents
    );
    // mock package.json
    fs.writeJsonSync(
      path.join(testSuluDir, "package.json"),
      mockSuluPackageJsonContents
    );
    // create a mock node_modules directory
    fs.emptyDirSync(path.join(testSuluDir, "node_modules"));
    // create a mock node_modules
    fs.emptyDirSync(path.join(testSuluDir, "node_modules", "node_module_1"));
    // create mock node_modules contents
    fs.writeFileSync(
      path.join(testSuluDir, "node_modules", "node_module_1", "index.js"),
      "mock node_module_1 contents"
    );
    // create mock yarn.lock file
    fs.writeFileSync(
      path.join(testSuluDir, "yarn.lock"),
      "mock yarn.lock contents"
    );
    fs.emptydirSync(path.join(testSuluDir, "cypress"));
    fs.writeFileSync(
      path.join(testSuluDir, "cypress", "index.spec.js"),
      "cypress test file"
    );

    // ---- plugin mocks ----

    // for each test plugin dir
    testPluginsDirsList.forEach((dir, i) => {
      // empty directory for plugin
      fs.emptyDirSync(dir);
      // mock manifest file for dir
      fs.writeJSONSync(
        path.join(dir, "suluPluginManifest.json"),
        mockPluginManifest
      );
      // mock package.json
      fs.writeJSONSync(
        path.join(dir, "package.json"),
        mockPluginPackageJsonContents
      );
      // src dir
      const srcdir = path.join(dir, "src");
      fs.emptydirSync(srcdir);
      // a js file that does not match pattern
      fs.writeFileSync(
        path.join(srcdir, "noPatternMatch.c"),
        "no pattern match file"
      );
      // a js file that matches pattern and does not match exclude pattern
      fs.writeFileSync(
        path.join(srcdir, "includePatternMatch.js"),
        mockPluginMatchContents[i]
      );
      // a js file that matches pattern and has the same name as a core sulu file
      fs.writeFileSync(
        path.join(srcdir, "overriden-file.js"),
        mockPluginOverridenFileContents[i]
      );
      // a js file that matches both pattern and exclude pattern
      fs.writeFileSync(
        path.join(srcdir, "includeExcludePatternMatch.js"),
        "include and exclude pattern match file"
      );
      // create a mock node_modules directory
      fs.emptyDirSync(path.join(dir, "node_modules"));
      // create a mock node_modules
      fs.emptyDirSync(path.join(dir, "node_modules", "node_module_mock"));
      // create mock node_modules contents
      fs.writeFileSync(
        path.join(dir, "node_modules", "node_module_mock", "index.js"),
        "mock node_module_mock contents"
      );
      // cypress dir
      const cyprdir = path.join(dir, "cypress");
      fs.emptydirSync(cyprdir);
      fs.writeFileSync(
        path.join(cyprdir, `plugin-${i}.spec.js`),
        "cypress test file"
      );
    });
  },
  afterEachTest: () => {
    const { testDir } = macros();
    fs.removeSync(testDir);
  },
};
