#!/usr/bin/env -S node -r esbin
import fs from "fs"
import { build } from "esbuild"
import { printSchema } from "graphql"
import type { Visitor } from "@babel/core"
import { getBasicOptions } from "./build-apps"
import { file } from "./utils"
import { dependencies, devDependencies } from "../package.json"
import type * as schema from "../src/background/graphql/schema"

const output = file.js()

const DEBUG = !!process.env.DEBUG

const babelPlugin: Visitor<{ filename: string }> = {
  ClassMethod({ node }) {
    node.params = []
    node.async = false
    node.body.body = []
  },
  ClassPrivateMethod(path) {
    path.remove()
  },
  ClassProperty({ node }) {
    node.value = null
  },
  FunctionDeclaration({ node }, { filename }) {
    if (!filename.includes("graphql")) {
      node.body.body = []
    }
  },
}

export async function buildSchema() {
  await build({
    ...getBasicOptions({
      entryPoints: ["src/background/graphql/schema.ts"],
      babelPlugins: [() => ({ visitor: babelPlugin })],
      plugins: [
        {
          name: "no-lib",
          setup(build) {
            const noop = require.resolve("lodash/noop")
            const whitelist = new Set([
              "graphql-type-json",
              "reflect-metadata",
              "tslib",
              "lodash",
              "@aet/gql-tools/marco",
              "@aet/gql-tools/type-graphql",
            ])
            const noopRes = { path: noop, external: false }

            build.onResolve({ filter: /.*/ }, ({ path }) => {
              if (
                path.includes("couchdb") ||
                path.includes("idb") ||
                path.includes("compiler") ||
                path.includes("webextension")
              ) {
                return noopRes
              }
              if (/^(~|\.\.?)\//.test(path)) {
                return null
              }
              if (whitelist.has(path)) {
                return { path: require.resolve(path), external: true }
              }
              return noopRes
            })
          },
        },
      ],
    }),
    outfile: output.path,
    target: "node20",
    format: "cjs",
    minify: !DEBUG,
    keepNames: true,
    legalComments: "none",
    sourcemap: false,
    splitting: false,
    external: Object.keys(dependencies || {})
      .concat(Object.keys(devDependencies))
      .concat("@aet/gql-tools/type-graphql"),
  })
    .then(() => {
      const { getSchema } = require("../" + output.path) as typeof schema
      const result = printSchema(getSchema())
      fs.writeFileSync("./src/generated/schema.gql", result)

      return result
    })
    .finally(() => {
      if (!DEBUG) {
        output.rm()
      }
    })
}

if (require.main === module) {
  void buildSchema()
}
