#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const tar = require("tar");
const gzip = require("zlib");
const zip = require("adm-zip");
const { https } = require("follow-redirects");
// version
// const VERSION = process.argv[2] ?? process.env.ACT_VERSION;
const VERSION = "0.2.59";
// Mapping between Node's `process.platform` to Golang's
const PLATFORM_MAPPING = {
  darwin: "Darwin",
  linux: "Linux",
  win32: "Windows",
};

// Mapping between Node's `process.platform` and `process.arch` to nektos/act compatible arch
const PLATFORM_TO_ARCH_MAPPING = {
  Darwin: {
    x64: "x86_64",
    arm64: "arm64",
  },
  Linux: {
    x64: "x86_64",
    arm64: "arm64",
    arm6: "armv6",
    arm7: "armv7",
  },
  Windows: {
    x64: "x86_64",
    arm64: "arm64",
    arm7: "armv7",
  },
};

const getBinPath = () => {
  let binPath = path.join("kie-act-js", "build", "bin", "act");
  if (process.platform == "win32") {
    binPath += ".exe";
  }
  return {
    binPath,
    binName: path.basename(binPath),
    binDir: path.dirname(binPath),
  };
};

const getDownloadUrl = () => {
  const platform = PLATFORM_MAPPING[process.platform];
  if (!platform) {
    throw Error(
      "Installation is not supported for this platform: " + process.platform
    );
  }
  let arch = PLATFORM_TO_ARCH_MAPPING[platform][process.arch];
  const armVersion = process.config.variables.arm_version;
  if (arch === "arm") {
    arch += armVersion;
  }
  if (!arch) {
    throw Error(
      "Installation is not supported for this architecture: " + process.arch
    );
  }
  // Build the download url from package.json
  const pkgName = "act";
  const repo = "nektos/act";
  let extension = "tar.gz";

  if (process.platform == "win32") {
    extension = "zip";
  }

  return `https://github.com/${repo}/releases/download/v0.2.59/${pkgName}_${platform}_${arch}.${extension}`;
};

const downloadWindows = async (url, binName, binDir) => {
  await new Promise((resolve, reject) => {
    https
      .get(url, (res) => {
        let buffer;

        res.on("data", (chunk) => {
          if (!buffer) {
            buffer = chunk;
          } else {
            buffer = Buffer.concat([buffer, chunk]);
          }
        });

        res.on("end", () => {
          // we have unzip for windows
          const unzip = new zip(buffer);
          unzip.extractEntryTo(unzip.getEntry(binName), binDir, false, true);
          resolve();
        });
      })
      .on("error", (err) => {
        console.log("Error: ", err.message);
        reject(
          "Unable to install act. Set ACT_BINARY enn variable to point to the path of your locally installed act"
        );
      });
  });
};

const downloadOthers = async (url, binName, binDir) => {
  // First we will un-gzip, then we will untar.
  const ungz = gzip.createGunzip();
  const untar = tar.x({ cwd: binDir }, [binName]);

  //   console.info("Downloading", url);

  https
    .get(url, (res) => {
      res.pipe(ungz).pipe(untar);
    })
    .on("error", (err) => {
      console.log("Error: ", err.message);
      throw "Unable to install act. Set ACT_BINARY enn variable to point to the path of your locally installed act";
    });

  await new Promise((resolve, reject) => {
    ungz.on("error", reject);
    untar.on("error", reject);
    untar.on("end", () => resolve());
  });
};

async function main() {
  const { binPath, binName, binDir } = getBinPath();
  const url = getDownloadUrl();
  await fs.promises.mkdir(binDir, { recursive: true });

  if (process.platform === "win32") {
    await downloadWindows(url, binName, binDir);
  } else {
    await downloadOthers(url, binName, binDir);
  }

  //   console.info("Installed act CLI successfully");
}

main();
