#!/usr/bin/env node

/**
 * check-circular-deps.mjs — detect circular imports across the SF codebase.
 *
 * Usage:
 *   npm run check:circular           # scan src/ + packages/
 *   npm run check:circular -- --ext  # scan extension source only
 *   node scripts/check-circular-deps.mjs [--ext] [--json]
 *
 * Exit 0 = no cycles found. Exit 1 = cycles detected (or scan error).
 */

import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import madge from "madge";

const __dirname = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dirname, "..");

const args = process.argv.slice(2);
const extOnly = args.includes("--ext");
const jsonOut = args.includes("--json");

const entries = extOnly
	? [resolve(root, "src/resources/extensions/sf")]
	: [resolve(root, "src"), resolve(root, "packages")];

console.error(
	`Scanning: ${entries.map((e) => e.replace(root + "/", "")).join(", ")}`,
);

let result;
try {
	result = await madge(entries, {
		fileExtensions: ["js", "mjs", "ts"],
		excludeRegExp: [
			/node_modules/,
			/\.test\.(js|mjs|ts)$/,
			/\/dist\//,
			/\/tests?\//,
		],
		detectiveOptions: {
			es6: { mixedImports: true, skipAsyncImports: true },
		},
	});
} catch (err) {
	console.error(`Scan failed: ${err.message}`);
	process.exit(1);
}

const cycles = result.circular();

if (jsonOut) {
	console.log(JSON.stringify({ cycles, count: cycles.length }, null, 2));
} else if (cycles.length === 0) {
	console.log("✅  No circular dependencies found.");
} else {
	console.log(`❌  ${cycles.length} circular dependency chain(s) found:\n`);
	for (const [i, chain] of cycles.entries()) {
		console.log(`  ${i + 1}. ${chain.join(" → ")} → ${chain[0]}`);
	}
}

process.exit(cycles.length > 0 ? 1 : 0);
