#!/usr/bin/env node

/**
 * Verify that dist/ contains no original source code after obfuscation.
 *
 * Checks that:
 * 1. Only expected files exist in dist/
 * 2. No .js files contain readable source patterns (comments, multi-line functions, etc.)
 */

import { readdirSync, readFileSync, statSync } from 'node:fs';
import { join } from 'node:path';

const DIST_DIR = join(process.cwd(), 'dist');

const ALLOWED_FILES = new Set([
  'index.cjs',
  'cli.cjs',
  'web-tree-sitter.wasm',
  'tree-sitter-cpp.wasm',
  'tree-sitter-c.wasm',
  'native/better_sqlite3.node',
]);

// Collect all files recursively
function walkDir(dir) {
  const files = [];
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    const fullPath = join(dir, entry.name);
    if (entry.isDirectory()) {
      files.push(...walkDir(fullPath));
    } else {
      files.push(fullPath);
    }
  }
  return files;
}

const allFiles = walkDir(DIST_DIR);
const violations = [];

// Check 1: No unexpected files or directories
for (const file of allFiles) {
  const relative = file.slice(DIST_DIR.length + 1).replace(/\\/g, '/');
  if (!ALLOWED_FILES.has(relative)) {
    violations.push(`Unexpected file in dist/: ${relative}`);
  }
}

// Check 2: The bundled .cjs file should not contain readable source patterns
const cjsPath = join(DIST_DIR, 'index.cjs');
if (statSync(cjsPath, { throwIfNoEntry: false })) {
  const content = readFileSync(cjsPath, 'utf-8');

  // Real ESM import/export at the top level (line starts with import/export).
  // Inside minified code these only appear within strings — never at the start of a line.
  if (/^import\s/m.test(content) || /^export\s/m.test(content)) {
    violations.push('index.cjs contains top-level ES module syntax (bundling may have failed)');
  }

  // A real sourceMappingURL directive starts at the beginning of a line (after optional whitespace)
  if (/^\s*\/\/[#@]\s*sourceMappingURL/m.test(content)) {
    violations.push('index.cjs contains source map reference');
  }

  // Original TypeScript source directories should not appear as-is in the bundle.
  // esbuild minification flattens everything — seeing "src/" paths as module references means
  // the original file structure leaked.
  const srcPathRefs = content.match(/require\(["']\.\/src\//g) || [];
  if (srcPathRefs.length > 0) {
    violations.push(`index.cjs contains ${srcPathRefs.length} require("./src/...") reference(s) — original directory structure leaked`);
  }
}

if (violations.length > 0) {
  console.error('[verify] Source exposure detected:');
  for (const v of violations) {
    console.error(`  - ${v}`);
  }
  process.exit(1);
}

console.log('[verify] OK — no source exposure in dist/');
