'use strict'

/**
 * Guards the JS loader entry points so a broken loader can never be published.
 *
 * This exists because 16.5.0 shipped an auto-generated CJS index.js inside a
 * "type": "module" package — its `import` condition then threw
 * `ReferenceError: require is not defined in ES module scope` for every ESM
 * consumer. A plain build/test pass did not catch it; this check would have.
 *
 * Static-only (no native .node required), so it runs anywhere incl. `verify`:
 *   1. package is "type": "module"
 *   2. exports["."].import → index.js is ESM (has `export`, no CJS require/module.exports)
 *   3. exports["."].require → index.cjs is CJS (has module.exports)
 *   4. neither shipped index.js nor index.d.ts still carries the napi auto-gen marker
 *   5. root index.{js,cjs,d.ts} are byte-identical to their loader/ canonical source
 *      (i.e. postbuild restored them and nothing drifted)
 */

const { readFileSync, existsSync } = require('fs')
const { join, resolve } = require('path')

const root = join(__dirname, '..')
const errors = []

function readJson(p) {
  return JSON.parse(readFileSync(p, 'utf8'))
}
function read(p) {
  return existsSync(p) ? readFileSync(p, 'utf8') : null
}

const AUTOGEN_MARKER = 'auto-generated by NAPI-RS'
const pkg = readJson(join(root, 'package.json'))

// 1. type: module
if (pkg.type !== 'module') {
  errors.push(`package.json "type" is "${pkg.type}", expected "module"`)
}

const dotExports = pkg.exports?.['.'] ?? {}
const importTarget = dotExports.import
const requireTarget = dotExports.require

// 2. ESM import entry
if (!importTarget) {
  errors.push('exports["."].import is missing')
} else {
  const p = resolve(root, importTarget)
  const src = read(p)
  if (src == null) {
    errors.push(`import entry ${importTarget} does not exist`)
  } else {
    if (src.includes(AUTOGEN_MARKER)) {
      errors.push(`import entry ${importTarget} is the napi auto-gen loader (CJS) — must be the ESM facade (loader/index.js). Run postbuild.`)
    }
    if (/\bmodule\.exports\b/.test(src) || /(^|\n)\s*const .*=\s*require\(/.test(src)) {
      errors.push(`import entry ${importTarget} uses CJS (module.exports/require) but the package is type:module — ESM import would throw at runtime`)
    }
    if (!/(^|\n)\s*export\s/.test(src)) {
      errors.push(`import entry ${importTarget} has no ESM \`export\` statements`)
    }
  }
}

// 3. CJS require entry
if (!requireTarget) {
  errors.push('exports["."].require is missing')
} else {
  const p = resolve(root, requireTarget)
  const src = read(p)
  if (src == null) {
    errors.push(`require entry ${requireTarget} does not exist`)
  } else if (!/\bmodule\.exports\b/.test(src)) {
    errors.push(`require entry ${requireTarget} has no module.exports — not a valid CJS loader`)
  }
}

// 4. no auto-gen marker in the shipped types
const dtsSrc = read(join(root, 'index.d.ts'))
if (dtsSrc && dtsSrc.includes(AUTOGEN_MARKER)) {
  errors.push('index.d.ts still carries the napi auto-gen marker — restore from loader/index.d.ts (postbuild)')
}

// 5. root loaders match their loader/ canonical source (no drift)
for (const f of ['index.js', 'index.cjs', 'index.d.ts']) {
  const canonical = read(join(root, 'loader', f))
  const shipped = read(join(root, f))
  if (canonical == null) {
    errors.push(`canonical source loader/${f} is missing — it is restored over the root after napi build`)
    continue
  }
  if (shipped == null) {
    errors.push(`root ${f} is missing`)
    continue
  }
  if (canonical !== shipped) {
    errors.push(`root ${f} differs from loader/${f} — run postbuild (or update loader/${f} if you changed the loader on purpose)`)
  }
}

if (errors.length) {
  console.error('loader:check failed:')
  for (const e of errors) console.error(`  • ${e}`)
  process.exit(1)
}

console.log('loader:check ok: ESM import + CJS require entries valid, no auto-gen drift')
