#!/usr/bin/env node
/* global console */
import { cp, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
import process from "node:process";

const scriptDir = dirname(fileURLToPath(import.meta.url));
const bundleRoot = resolve(scriptDir, "..");
const args = process.argv.slice(2);
const positional = args.filter((arg) => !arg.startsWith("--"));
const target = resolve(positional[0] ?? process.cwd());
const flags = new Set(args.filter((arg) => arg.startsWith("--")));
const install = flags.has("--install");
const force = flags.has("--force");
const withShowcase = flags.has("--with-showcase");
const withManaged = flags.has("--with-managed-service");
const runChecks = flags.has("--check");

if (!install) {
  console.log(
    "Dry run: captcha installation would update the target repository. Re-run with --install to apply it.",
  );
  process.exit(0);
}

async function exists(path) {
  try {
    await stat(path);
    return true;
  } catch {
    return false;
  }
}
async function copyDirectory(source, destination) {
  if ((await exists(destination)) && force) await rm(destination, { recursive: true, force: true });
  await mkdir(dirname(destination), { recursive: true });
  await cp(source, destination, { recursive: true, force: true });
}
async function readJson(path) {
  return JSON.parse(await readFile(path, "utf8"));
}
async function writeJson(path, value) {
  await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
}
async function run(command, commandArgs) {
  await new Promise((resolvePromise, reject) => {
    const child = spawn(command, commandArgs, {
      cwd: target,
      stdio: "inherit",
      shell: process.platform === "win32",
    });
    child.on("exit", (code) =>
      code === 0 ? resolvePromise() : reject(new Error(`${command} exited with ${code}`)),
    );
    child.on("error", reject);
  });
}

if (!(await exists(join(target, "packages"))) || !(await exists(join(target, "tsconfig.json")))) {
  throw new Error(`Target does not look like a WRNexusJS repository: ${target}`);
}

await copyDirectory(join(bundleRoot, "packages/captcha"), join(target, "packages/captcha"));

// WRNexusJS 0.4 discovers package-owned components and browser runtimes through
// package.json `wrnexus` metadata. Do not copy Captcha.wrn or captcha.js into the
// UI/public directories: doing so creates stale duplicates that bypass package
// upgrades and content-hashed production assets.

if (withShowcase)
  await copyDirectory(
    join(bundleRoot, "examples/captcha-showcase"),
    join(target, "examples/captcha-showcase"),
  );
if (withManaged)
  await copyDirectory(
    join(bundleRoot, "services/managed-captcha"),
    join(target, "services/managed-captcha"),
  );

const tsconfigPath = join(target, "tsconfig.json");
const tsconfig = await readJson(tsconfigPath);
tsconfig.compilerOptions ??= {};
tsconfig.compilerOptions.paths ??= {};
Object.assign(tsconfig.compilerOptions.paths, {
  "@wrnexus/captcha": ["./packages/captcha/src/index.ts"],
  "@wrnexus/captcha/server": ["./packages/captcha/src/server/index.ts"],
  "@wrnexus/captcha/client": ["./packages/captcha/src/client/index.ts"],
  "@wrnexus/captcha/plugin": ["./packages/captcha/src/plugin.ts"],
  "@wrnexus/captcha/*": ["./packages/captcha/src/*"],
});
await writeJson(tsconfigPath, tsconfig);

if (withManaged) {
  const packagePath = join(target, "package.json");
  const packageJson = await readJson(packagePath);
  packageJson.workspaces ??= ["packages/*", "examples/*"];
  if (!packageJson.workspaces.includes("services/*")) packageJson.workspaces.push("services/*");
  await writeJson(packagePath, packageJson);
}

console.log("Installed @wrnexus/captcha.");
console.log("Canonical package: packages/captcha");
console.log("Component/runtime discovery: automatic through package.json wrnexus.plugin");
console.log("No public captcha.js or UI component copy is required.");

if (runChecks) {
  await run("bun", ["install"]);
  await run("bun", ["run", "scripts/generate-ui-component-reference.mjs"]);
  await run("bun", ["test", "packages/captcha"]);
  if (withManaged) await run("bun", ["test", "services/managed-captcha"]);
  await run("bun", ["run", "typecheck"]);
  if (withShowcase) await run("bun", ["run", "--cwd", "examples/captcha-showcase", "check"]);
}
