#!/usr/bin/env -S node -r esbin
import { promises as fs } from "node:fs"
import { format } from "prettier"
import { CodeFileLoader } from "@graphql-tools/code-file-loader"
import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader"
import * as typescript from "@graphql-codegen/typescript"
import * as typescriptOperations from "@graphql-codegen/typescript-operations"
import * as add from "@graphql-codegen/add"
import { plugin as _, codegen, typedDocumentNodePlugin } from "@aet/gql-tools/codegen"
import { buildSchema } from "./build-schema-file"

async function main() {
  await buildSchema()

  const scalars: Record<string, string> = {
    DateTime: "Date",
  }

  const context = await codegen({
    schema: {
      source: "./src/generated/schema.gql",
      loaders: [new GraphQLFileLoader()],
    },
    documents: {
      source: ["./src/**/*.{ts,tsx}", "!/src/generated/**/*.{ts,tsx}"],
      loaders: [new CodeFileLoader({ pluckConfig: { skipIndent: true } })],
    },
  })

  const content = await context.generate({
    plugins: [
      _(typescript, {
        immutableTypes: true,
        useTypeImports: true,
        declarationKind: "interface",
        allowEnumStringTypes: true,
        enumsAsTypes: true,
        scalars,
      }),
      _(typescriptOperations, {
        declarationKind: "interface",
        allowEnumStringTypes: true,
        scalars,
      }),
      _(add, {
        content: /* js */ `
          /* eslint-disable */
          import { gql as _gql } from "@apollo/client";
          import type { DocumentNode } from "graphql";
          export { ApolloClient, useQuery, useApolloClient, useLazyQuery, useMutation } from "@apollo/client";

          export const gql = _gql as unknown as {
            <K extends keyof DocumentMap>(
              literals: string | readonly string[],
              ...args: any[]
            ): DocumentMap[K];
            (
              literals: string | readonly string[],
              ...args: any[]
            ): DocumentNode;
          }
        `,
      }),
      _(typedDocumentNodePlugin, {
        createDocumentMap: true,
        exportDocumentNodes: true,
      }),
    ],
    pipeline: [
      source =>
        source
          .replace(/Scalars\['String']\['(in|out)put']/g, "string")
          .replace(/Scalars\['ID']\['(in|out)put']/g, "string")
          .replace(/Scalars\['Boolean']\['(in|out)put']/g, "boolean")
          .replace(/Scalars\['Int']\['(in|out)put']/g, "number")
          .replace(/Scalars\['Float']\['(in|out)put']/g, "number")
          .replaceAll("Scalars['DateTime']['input']", "Date")
          .replaceAll("Scalars['JSON']['input']", "any")
          .replace(/(\w+) \| `\$\{\1}`/g, " $1")
          .replace(/: (Input)?Maybe<([['\]\w<> ]+)>/g, ": $2 | null")
          .replace(/: Array<([\w<> ]+)>/g, ": $1[]")
          .replace(/export type (\w+) = {/g, "export interface $1 {")
          .replace(/export type (Make|Maybe|InputMaybe|Exact|Incremental)/g, "type $1"),
      code => format(code, { parser: "typescript" }),
    ],
  })

  await fs.writeFile("./src/generated/graphql.ts", content)
}

void main()
