import { build, type Plugin } from 'vite'
import { readdirSync, statSync, rmSync, mkdirSync } from 'node:fs'
import { join, parse } from 'node:path'

// plugin to handle worker imports from linked packages by treating them as external
function handleLinkedWorkers(): Plugin {
  return {
    name: 'handle-linked-workers',
    enforce: 'pre',
    load(id) {
      // Intercept worker URLs from linked packages (outside node_modules)
      if (id.includes('?worker') && !id.includes('node_modules')) {
        return 'export default {}'
      }
      return null
    },
    transform(code, id) {
      // skip worker-import-meta-url processing for files outside project
      if (!id.startsWith(process.cwd()) && id.includes('/nostr-gadgets/')) {
        // replace new Worker() calls with a stub that won't crash
        const transformed = code.replace(
          /new Worker\(new URL\([^)]+\),[^)]+\)/g,
          '({ postMessage() {}, terminate() {} })',
        )
        return { code: transformed, map: null }
      }
      return null
    },
  }
}

// get all TypeScript files in the root directory (excluding build script)
const all = readdirSync(process.cwd()).filter(
  file => file.endsWith('.ts') && file !== 'build.ts' && statSync(join(process.cwd(), file)).isFile(),
)

// get component files (nostr-*.ts)
const components = all.filter(file => file.startsWith('nostr-'))

// create entry object for all files: { 'nostr-name': 'nostr-name.ts', 'utils': 'utils.ts', ... }
const allEntries = Object.fromEntries(all.map(file => [parse(file).name, file]))

async function main() {
  // clean output directories
  rmSync('dist', { recursive: true, force: true })
  rmSync('lib', { recursive: true, force: true })
  mkdirSync('dist', { recursive: true })
  mkdirSync('lib', { recursive: true })

  // build big IIFE bundle (index.ts with all components)
  console.log('building bundle: index.js')
  await build({
    configFile: false,
    build: {
      emptyOutDir: false,
      lib: {
        entry: 'index.ts',
        formats: ['iife'],
        name: 'NostrWebComponents',
        fileName: () => 'index.js',
      },
      outDir: 'dist',
      sourcemap: true,
    },
    plugins: [handleLinkedWorkers()],
  })

  // build ESM library files for all TypeScript files
  console.log('building lib: ESM modules')
  await build({
    configFile: false,
    build: {
      emptyOutDir: false,
      outDir: 'lib',
      sourcemap: true,
      rollupOptions: {
        input: allEntries,
        external: (id: string, parentId: string | undefined) => {
          // Entry points should never be external
          if (!parentId) return false
          // Local relative imports should not be external
          if (id.startsWith('.') || id.startsWith('/')) return false
          // Everything else (npm packages) should be external
          return true
        },
        output: {
          format: 'es',
          entryFileNames: '[name].js',
          chunkFileNames: '[name].js',
        },
      },
    },
    plugins: [handleLinkedWorkers()],
  })

  // build individual IIFE bundles for each component
  await Promise.all(
    components.map(async component => {
      const name = parse(component).name
      console.log(`building component: ${name}`)
      await build({
        configFile: false,
        build: {
          emptyOutDir: false,
          lib: {
            entry: component,
            formats: ['iife'],
            name: name.replace(/-/g, '_'),
            fileName: () => `${name}.js`,
          },
          outDir: 'dist',
          sourcemap: true,
        },
        plugins: [handleLinkedWorkers()],
      })
    }),
  )

  console.log('build complete!')
}

main().catch(err => {
  console.error(err)
  process.exit(1)
})
