import { dirname } from "path"
import glob from "fast-glob"
import type { types } from "@babel/core"
import type { BabelPlugin } from "./esbuild-babel"

const skip = new WeakSet<types.CallExpression>()

export const dynamicImport =
  (filePath: string): BabelPlugin =>
  ({ types: t }) => ({
    name: "dynamic-import",
    visitor: {
      Import(path) {
        if (
          !t.isCallExpression(path.parent) ||
          path.parent.arguments.length !== 1 ||
          skip.has(path.parent)
        ) {
          return
        }

        const [arg] = path.parent.arguments
        if (!t.isTemplateLiteral(arg)) {
          return
        }

        const key = path.scope.generateDeclaredUidIdentifier("key")

        const globText = arg.quasis.map(x => x.value.raw).join("*")
        const globCandidates = glob.sync(globText, {
          cwd: dirname(filePath),
        })

        const clone = t.cloneNode(path.parent, true)
        skip.add(clone)

        const cond = globCandidates.reduceRight(
          (accum: types.Expression, cur) =>
            t.conditionalExpression(
              t.binaryExpression("===", key, t.stringLiteral(cur)),
              t.callExpression(t.import(), [t.stringLiteral(cur)]),
              accum,
            ),
          clone,
        )

        t.cloneNode(path.parent)

        path.parentPath.replaceWith(
          t.sequenceExpression([t.assignmentExpression("=", key, arg), cond]),
        )
      },
    },
  })
