#!/usr/bin/env node

// the .mjs extension is important
// run this inside the directory containing the `elm.json` file
// (if it's not executable, run `chmod +x elm-build-cache.mjs`)
// with VERBOSE=1 env var it will show you results of the exec commands

import fs from 'fs/promises';
import {exec} from 'child_process';

const tempDir = 'elm-stuff/elm-build-cache';

const shouldLog = process.env.VERBOSE === '1'; // false; // true;
const ourExec = async (cmd) => 
  new Promise((resolve, reject) => {
    exec(cmd, (error,stdout,stderr) => {
      if (error) reject(error);
      if (shouldLog) console.log({cmd,stdout,stderr});
      resolve([stdout,stderr]);
    });
  });

const downloadDependency = async ([pkg,version]) => {
  const pkgWithDash = pkg.replace('/','-');

  const zipballUrl = `https://github.com/${pkg}/zipball/${version}/`;
  const zipballPath = `${tempDir}/${pkgWithDash}-${version}.zip`;

  // based on info in https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/
  const elmHome = process.env.ELM_HOME ?? process.platform === 'win32' ? `${process.env.APPDATA}/elm` : `~/.elm`;
  const packagePath = `${elmHome}/0.19.1/packages/${pkg}/${version}`;

  await ourExec(`mkdir -p ${tempDir}`);
  await ourExec(`rm -rf ${packagePath}`);
  await ourExec(`mkdir -p ${packagePath}`);
  await ourExec(`curl -L ${zipballUrl} -o ${zipballPath}`);
  await ourExec(`unzip ${zipballPath} -d ${tempDir}`);
  await ourExec(`mv ${tempDir}/${pkgWithDash}-*/* ${packagePath}`);
  await ourExec(`rm -rf '${zipballPath}'`);
}

const pickLowerBound = version => version.slice(0,version.indexOf(' '));
const getPackageDeps = elmJson => 
  Object.fromEntries(
    [
      ...Object.entries(elmJson.dependencies),
      ...Object.entries(elmJson['test-dependencies']),
    ].map(([k,v]) => [k,pickLowerBound(v)])
  );
const getAppDeps = elmJson => ({
  ...elmJson.dependencies.direct, 
  ...elmJson.dependencies.indirect,
  ...elmJson['test-dependencies'].direct, 
  ...elmJson['test-dependencies'].indirect,
});
const getElmJsonDeps = elmJson => 
  elmJson.type === 'application' 
    ? getAppDeps(elmJson) 
    : getPackageDeps(elmJson);

const main = async () => {
  const elmJson = JSON.parse(await fs.readFile('./elm.json','utf-8'));
  const deps = getElmJsonDeps(elmJson);
  console.log({deps});
  await Promise.all(Object.entries(deps).map(downloadDependency));
}

await ourExec(`rm -rf '${tempDir}'`);
await main();
await ourExec(`rm -rf '${tempDir}'`);