#!/usr/bin/env node
import { promises as fs } from "fs";
import path from "path";
import { fileURLToPath } from "url";
import JavaScriptObfuscator from "javascript-obfuscator";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const rootDir = path.resolve(__dirname, "..");
const distDir = path.join(rootDir, "dist");

const copyTargets = [
  { from: path.join(rootDir, "index.js"), to: path.join(distDir, "index.js") },
  { from: path.join(rootDir, "lib"), to: path.join(distDir, "lib") },
  { from: path.join(rootDir, "bin"), to: path.join(distDir, "bin") }
];

async function main() {
  await fs.rm(distDir, { recursive: true, force: true });
  await fs.mkdir(distDir, { recursive: true });

  for (const target of copyTargets) {
    await copy(target.from, target.to);
  }

  await obfuscateDirectory(distDir);
  console.log("Obfuscated build written to", distDir);
}

async function copy(src, dest) {
  const stat = await fs.stat(src);
  if (stat.isDirectory()) {
    await fs.mkdir(dest, { recursive: true });
    const entries = await fs.readdir(src);
    for (const entry of entries) {
      await copy(path.join(src, entry), path.join(dest, entry));
    }
    return;
  }

  await fs.copyFile(src, dest);
}

async function obfuscateDirectory(dir) {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  await Promise.all(
    entries.map(async entry => {
      const entryPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        await obfuscateDirectory(entryPath);
        return;
      }

      if (entry.isFile() && entry.name.endsWith(".js")) {
        await obfuscateFile(entryPath);
      }
    })
  );
}

async function obfuscateFile(filePath) {
  const original = await fs.readFile(filePath, "utf8");
  const { shebang, body } = extractShebang(original);
  const obfuscated = JavaScriptObfuscator.obfuscate(body, {
    compact: true,
    controlFlowFlattening: true,
    stringArray: true,
    stringArrayEncoding: ["base64"],
    deadCodeInjection: true,
    target: "node",
    identifierNamesGenerator: "hexadecimal"
  });

  const content = shebang
    ? `${shebang}\n${obfuscated.getObfuscatedCode()}`
    : obfuscated.getObfuscatedCode();
  await fs.writeFile(filePath, content, "utf8");
}

function extractShebang(source) {
  if (!source.startsWith("#!")) {
    return { body: source };
  }

  const newlineIndex = source.indexOf("\n");
  if (newlineIndex === -1) {
    return { shebang: source, body: "" };
  }

  return {
    shebang: source.slice(0, newlineIndex),
    body: source.slice(newlineIndex + 1)
  };
}

main().catch(err => {
  console.error("Build failed:");
  console.error(err);
  process.exitCode = 1;
});
