import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { execFileSync } from 'node:child_process'
import { createRequire } from 'node:module'

const require = createRequire(import.meta.url)
const { rollup } = require('rollup')
const replace = require('@rollup/plugin-replace')
const typescript = require('@rollup/plugin-typescript')
const terser = require('@rollup/plugin-terser')

const pkg = JSON.parse(readFileSync('package.json', 'utf8'))
const version = process.env.VERSION || pkg.version
const year = new Date().getFullYear()
const banner = `/**
 * Fuse.js v${version} - ${pkg.description} (${pkg.homepage})
 *
 * Copyright (c) ${year} ${pkg.author.name} (${pkg.author.url})
 * All Rights Reserved. Apache Software License 2.0
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 */`

const full = { LOGICAL: 'true', EXTENDED: 'true', TOKEN: 'true' }
const basic = { LOGICAL: 'false', EXTENDED: 'false', TOKEN: 'false' }

function define(flags, env, workerIsCjs = 'false') {
  return {
    preventAssignment: true,
    values: {
      __VERSION__: JSON.stringify(version),
      __WORKER_IS_CJS__: workerIsCjs,
      'process.env.NODE_ENV': JSON.stringify(env),
      'process.env.LOGICAL_SEARCH_ENABLED': flags.LOGICAL,
      'process.env.EXTENDED_SEARCH_ENABLED': flags.EXTENDED,
      'process.env.TOKEN_SEARCH_ENABLED': flags.TOKEN
    }
  }
}

async function build(input, file, format, flags, env, options = {}) {
  const bundle = await rollup({
    input,
    plugins: [
      replace(define(flags, env, options.workerIsCjs || 'false')),
      typescript({
        tsconfig: './tsconfig.base.json',
        include: ['src/**/*.ts'],
        noEmitOnError: false,
        declaration: false,
        declarationMap: false,
        sourceMap: false
      })
    ],
    treeshake: true
  })

  await bundle.write({
    file,
    format,
    banner,
    exports: options.exports || 'auto',
    plugins: options.minify ? [terser()] : []
  })
  await bundle.close()
}

rmSync('dist', { recursive: true, force: true })
mkdirSync('dist', { recursive: true })

await build('src/entry.ts', 'dist/fuse.cjs', 'cjs', full, 'development', {
  exports: 'default'
})
await build('src/entry.ts', 'dist/fuse.mjs', 'esm', full, 'development')
await build('src/entry.ts', 'dist/fuse.min.cjs', 'cjs', full, 'production', {
  exports: 'default',
  minify: true
})
await build('src/entry.ts', 'dist/fuse.min.mjs', 'esm', full, 'production', {
  minify: true
})

await build('src/entry.ts', 'dist/fuse.basic.cjs', 'cjs', basic, 'development', {
  exports: 'default'
})
await build('src/entry.ts', 'dist/fuse.basic.mjs', 'esm', basic, 'development')
await build('src/entry.ts', 'dist/fuse.basic.min.cjs', 'cjs', basic, 'production', {
  exports: 'default',
  minify: true
})
await build('src/entry.ts', 'dist/fuse.basic.min.mjs', 'esm', basic, 'production', {
  minify: true
})

await build('src/workers/index.ts', 'dist/fuse-worker.cjs', 'cjs', full, 'production', {
  exports: 'named',
  workerIsCjs: 'true'
})
await build('src/workers/index.ts', 'dist/fuse-worker.mjs', 'esm', full, 'production')
await build('src/workers/worker.ts', 'dist/fuse.worker.mjs', 'esm', full, 'production')
await build('src/workers/worker.ts', 'dist/fuse.worker.min.mjs', 'esm', full, 'production', {
  minify: true
})

execFileSync(
  'tsc',
  [
    '-p',
    'src/tsconfig.json',
    '--noEmit',
    'false',
    '--emitDeclarationOnly',
    '--declaration',
    'true',
    '--declarationDir',
    'dist'
  ],
  { stdio: 'inherit' }
)

copyFileSync('dist/entry.d.ts', 'dist/fuse.d.ts')
copyFileSync('dist/entry.d.ts', 'dist/fuse.d.cts')
copyFileSync('dist/workers/index.d.ts', 'dist/fuse-worker.d.ts')
copyFileSync('dist/workers/index.d.ts', 'dist/fuse-worker.d.cts')
writeFileSync(
  'dist/fuse.worker.d.ts',
  'declare const workerScriptUrl: string\nexport default workerScriptUrl\n'
)
