#!/usr/bin/env -S node -r esbin
import { promises as fs } from "fs"
import { resolve } from "path"
import { kebabCase } from "lodash"
import { sync as glob } from "fast-glob"
import { ensureArray as arr } from "~/shared/ensureArray"
// import _ from "dedent";

interface Task {
  deps: string | string[]
  target: string | string[]
  command: string | string[]
}

// Variables for Makefile
// $@: The file name of the target of the rule.
// $<: The name of the first prerequisite.
// $?: The names of all the prerequisites that are newer than the target, with spaces between them.
// $^: The names of all the prerequisites, with spaces between them.

const tasks: { [name: string]: () => Task } = {
  Makefile: (script = "scripts/build-makefile.ts") => ({
    command: script,
    target: "Makefile",
    deps: [script],
  }),

  theme: (script = "scripts/build-theme.tsx") => ({
    command: `${script} -o $(@D)`,
    target: [
      "src/shared/theme/tokens.generated.ts",
      "src/shared/theme/tokens.generated.css",
    ],
    deps: ["src/shared/theme/tokens.tsx", script],
  }),

  models: (
    models = "src/shared/models",
    source = `${models}/models.yml`,
    script = "./scripts/build-models.ts",
  ) => ({
    command: `${script}`,
    target: glob(`${models}/*.generated.ts`),
    deps: [source, script],
  }),

  WebExtensionPolyfill: (base = "src/vendor/webextension-polyfill") => ({
    target: `${base}/api-metadata.generated.json`,
    deps: glob(`${base}/**/*`),
    command: `./${base}/scripts/compress.ts`,
  }),

  HTML: (script = "scripts/build-htmls.tsx") => ({
    target: glob("dist/*.html"),
    deps: script,
    command: script,
  }),

  locales: (script = "scripts/build-locales.ts") => ({
    target: [
      ...glob(["dist/_locales/**/*.json", "src/shared/i18n/resources"]),
      "src/shared/i18n/data.generated.ts",
    ],
    deps: script,
    command: script,
  }),

  // monaco: (
  //   script = "./scripts/build-monaco.ts",
  //   dist = "dist/vendor/monaco-editor/index.js",
  // ) => ({
  //   target: dist,
  //   deps: ["package.json", script],
  //   command: [script, `touch ${dist}`],
  // }),

  sass: (script = "./scripts/build-sass.ts") => ({
    target: "dist/vendor/sass/index.js",
    deps: ["package.json", script],
    command: script,
  }),
}

async function main() {
  const sep = " \\\n  "

  function* generate() {
    yield "# This file is generated by `make Makefile`"

    const instances = Object.entries(tasks).map(([name, t]) => [name, t()] as const)
    for (const [name, task] of instances) {
      const { target } = task
      yield arr(target).join(" ") +
        ": " +
        arr(task.deps)
          .filter(d => !glob(d).some(file => target.includes(file)))
          .join(sep)

      yield `\t@echo "✨ Building ${name}..."`
      for (const cmd of arr(task.command)) {
        yield `\t@${cmd}`
      }
      yield ""
      yield `${kebabCase(name)}: ${arr(target)[0]}`
      yield ""
    }

    yield "all: " + instances.map(task => kebabCase(task[0])).join(sep)
    yield ""
  }

  const makefile = [...generate()].join("\n")
  await fs.writeFile(resolve(__dirname, "../Makefile"), makefile)
}

main()
