const { describe, it, beforeEach, afterEach } = require("mocha");
// const { transferSulu } = require("./transferSulu");
const { transferPlugin } = require("./transferPlugins");
const assert = require("assert");
const fs = require("fs-extra");
const path = require("path");

const {
  macros,
  beforeEachTest,
  afterEachTest,
} = require("../../resources/tests");
const { coreLogic } = require("./coreLogic");

const {
  testSuluDir,
  testWriteResultDir,
  log,
  mockPluginManifest,
  testPluginsDirsList,
  mockPluginMatchContents,
  mockPluginOverridenFileContents,
} = macros();

const manifestPath = path.join(testWriteResultDir, "buildManifest.json");

describe("src/libs/stage1/coreLogic.spec.js", () => {
  beforeEach(() => {
    beforeEachTest();
    coreLogic({
      incrementalBuild: false,
      buildOutputPath: testWriteResultDir,
      version: null,
      log,
      suluDir: testSuluDir,
      manifests: [
        {
          absolutePath: testPluginsDirsList[0],
          manifest: mockPluginManifest,
        },
      ],
      revision: "test",
    });
  });

  afterEach(() => {
    afterEachTest();
  });

  describe("coreLogic(), non-incremental build", () => {
    it("should not transfer the file that does not match the pattern", () => {
      const srcfiles = fs.readdirSync(path.join(testWriteResultDir, "src"));
      assert.equal(srcfiles.includes("noPatternMatch.c"), false);
    });
    it("should include package.json", () => {
      const rootfiles = fs.readdirSync(testWriteResultDir);
      assert.equal(rootfiles.includes("package.json"), true);
    });
    it("should transfer file that matches the pattern", () => {
      const srcfiles = fs.readdirSync(path.join(testWriteResultDir, "src"));
      assert.equal(srcfiles.includes("includePatternMatch.js"), true);
    });
    it("should not transfer file that matches the pattern and matches exclude pattern", () => {
      const srcfiles = fs.readdirSync(path.join(testWriteResultDir, "src"));
      assert.equal(srcfiles.includes("includeExcludePatternMatch.js"), false);
    });
    it("should not transfer anything out of node_modules", () => {
      const srcfiles = fs.readdirSync(path.join(testWriteResultDir, "src"));
      assert.equal(srcfiles.includes("node_modules"), false);
    });
    it("should correctly override a core repository file with first plugin file of same name", () => {
      const read = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "overriden-file.js")
        )
        .toString();
      assert.equal(read, mockPluginOverridenFileContents[0]);
    });
    it("should correctly override a first plugin file with second plugin file of same name", () => {
      const beforeOverride = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "includePatternMatch.js")
        )
        .toString();
      assert.deepEqual(beforeOverride, mockPluginMatchContents[0]);
      transferPlugin({
        manifest: {
          absolutePath: testPluginsDirsList[1],
          manifest: mockPluginManifest,
        },
        buildOutputPath: testWriteResultDir,
        log,
        buildManifest: {},
        revision: null,
      });
      const afterOverride = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "includePatternMatch.js")
        )
        .toString();
      assert.deepEqual(afterOverride, mockPluginMatchContents[1]);
    });
    it("should correctly double override a core repository file overriden by first plugin file with second plugin file of same name", () => {
      const read = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "overriden-file.js")
        )
        .toString();
      assert.equal(read, mockPluginOverridenFileContents[0]);

      transferPlugin({
        manifest: {
          absolutePath: testPluginsDirsList[1],
          manifest: mockPluginManifest,
        },
        buildOutputPath: testWriteResultDir,
        log,
        buildManifest: {},
        revision: null,
      });
      const read2 = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "overriden-file.js")
        )
        .toString();
      assert.equal(read2, mockPluginOverridenFileContents[1]);
    });
    it("should transfer files from cypress folder (so not just root)", () => {
      const rootfiles = fs.readdirSync(testWriteResultDir);
      assert.ok(rootfiles.includes("cypress"));
      const cyprFiles = fs.readdirSync(
        path.join(testWriteResultDir, "cypress")
      );
      assert.deepStrictEqual(cyprFiles, ["index.spec.js", "plugin-0.spec.js"]);
    });
    it("should have build create a manifest", () => {
      assert.ok(fs.existsSync(manifestPath));
    });
    it("should have build manifest have core sulu index file", () => {
      const manifest = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, value] = Object.entries(manifest).find(([key]) => key.includes("index.js"));
      assert.equal(value.by, "sulu");
    });
    it("should have build manifest have plugin overriden file", () => {
      const manifest = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, value] = Object.entries(manifest).find(([key]) => key.includes("overriden-file.js"));
      assert.equal(value.by, "plugin-1");
    });
    it("should have second revision build clean slate, create new files and create new build manifest", () => {
      const p = path.join(
        testWriteResultDir,
        "src",
        "includePatternMatch.js"
      );
      const read1 = fs.readFileSync(p).toString();
      const manifest1 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v1] = Object.entries(manifest1).find(([key]) => key.includes("index.js"));
      assert.equal(v1.revision, "test");

      coreLogic({
        incrementalBuild: false,
        buildOutputPath: testWriteResultDir,
        version: null,
        log,
        suluDir: testSuluDir,
        manifests: [
          {
            absolutePath: testPluginsDirsList[0],
            manifest: mockPluginManifest,
          },
        ],
        revision: "test-2",
      });

      const read2 = fs.readFileSync(p).toString();
      const manifest2 = JSON.parse(fs.readFileSync(manifestPath).toString());

      assert.equal(read1, read2);
      const [, v2] = Object.entries(manifest2).find(([key]) => key.includes("index.js"));
      assert.equal(v2.revision, "test-2");
    });
  });
  describe("coreLogin(), incremental build", () => {
    it("should have plugin override core sulu files if the file timestamp didnt change", () => {
      const manifest1 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v1] = Object.entries(manifest1).find(([key]) => key.includes("index.js"));
      assert.equal(v1.revision, "test");
      coreLogic({
        incrementalBuild: true,
        buildOutputPath: testWriteResultDir,
        version: null,
        log,
        suluDir: testSuluDir,
        manifests: [
          {
            absolutePath: testPluginsDirsList[0],
            manifest: mockPluginManifest,
          },
        ],
        revision: "test-2",
      });

      const manifest2 = JSON.parse(fs.readFileSync(manifestPath).toString());

      const [, v2] = Object.entries(manifest2).find(([key]) => key.includes("index.js"));
      assert.equal(v2.revision, "test");
    });
    it("should have second revision not override old files if the file timestamp didnt change", () => {
      const manifest1 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v1] = Object.entries(manifest1).find(([key]) => key.includes("index.js"));
      assert.equal(v1.revision, "test");
      coreLogic({
        incrementalBuild: true,
        buildOutputPath: testWriteResultDir,
        version: null,
        log,
        suluDir: testSuluDir,
        manifests: [
          {
            absolutePath: testPluginsDirsList[0],
            manifest: mockPluginManifest,
          },
        ],
        revision: "test-2",
      });

      const manifest2 = JSON.parse(fs.readFileSync(manifestPath).toString());

      const [, v2] = Object.entries(manifest2).find(([key]) => key.includes("index.js"));
      assert.equal(v2.revision, "test");
    });
    it("should have second revision keep first revision's override of core sulu files", () => {
      const read = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "overriden-file.js")
        )
        .toString();
      assert.equal(read, mockPluginOverridenFileContents[0]);
      const manifest1 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v1] = Object.entries(manifest1).find(([key]) => key.includes("overriden-file.js"));
      assert.equal(v1.revision, "test");
      assert.equal(v1.by, "plugin-1");
      coreLogic({
        incrementalBuild: true,
        buildOutputPath: testWriteResultDir,
        version: null,
        log,
        suluDir: testSuluDir,
        manifests: [
          {
            absolutePath: testPluginsDirsList[0],
            manifest: mockPluginManifest,
          },
        ],
        revision: "test-2",
      });
      const manifest2 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v2] = Object.entries(manifest2).find(([key]) => key.includes("overriden-file.js"));
      assert.equal(v2.revision, "test");
      assert.equal(v2.by, "plugin-1");
    });
    it("should have second revision override first revision's override of core sulu files due to changed contents", () => {
      const read = fs
        .readFileSync(
          path.join(testWriteResultDir, "src", "overriden-file.js")
        )
        .toString();
      assert.equal(read, mockPluginOverridenFileContents[0]);
      const manifest1 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v1] = Object.entries(manifest1).find(([key]) => key.includes("overriden-file.js"));
      assert.equal(v1.revision, "test");
      assert.equal(v1.by, "plugin-1");
      fs.writeFileSync(
        path.join(testPluginsDirsList[0], "src", "overriden-file.js"),
        "second revision override"
      );
      coreLogic({
        incrementalBuild: true,
        buildOutputPath: testWriteResultDir,
        version: null,
        log,
        suluDir: testSuluDir,
        manifests: [
          {
            absolutePath: testPluginsDirsList[0],
            manifest: mockPluginManifest,
          },
        ],
        revision: "test-2",
      });
      const manifest2 = JSON.parse(fs.readFileSync(manifestPath).toString());
      const [, v2] = Object.entries(manifest2).find(([key]) => key.includes("overriden-file.js"));
      assert.equal(v2.revision, "test-2");
      assert.equal(v2.by, "plugin-1");
    });
  });
});
