import { describe, expect, it } from "vitest";

import {
	bundledPackages,
	comparePackages,
	formatDiff,
	packageFromSource,
	recordedPackages,
} from "./bundledPackages.mjs";

describe("packageFromSource", () => {
	it("reads a plain package name", () => {
		expect(packageFromSource("../../node_modules/react-dom/client.js")).toBe("react-dom");
	});

	it("keeps the scope of a scoped package", () => {
		expect(packageFromSource("../../node_modules/@tanstack/react-query/build/index.js")).toBe(
			"@tanstack/react-query",
		);
	});

	it("takes the last node_modules, so a nested dependency is named correctly", () => {
		expect(packageFromSource("node_modules/vite/node_modules/@scope/inner/x.js")).toBe("@scope/inner");
	});

	it("ignores application sources", () => {
		expect(packageFromSource("src/lib/api.ts")).toBeNull();
		expect(packageFromSource("../src/main.tsx")).toBeNull();
	});
});

describe("bundledPackages", () => {
	it("sorts and deduplicates across every map", () => {
		const packages = bundledPackages([
			["node_modules/react/index.js", "src/main.tsx", "node_modules/react/jsx-runtime.js"],
			["node_modules/@tanstack/react-router/x.js", "node_modules/react/index.js"],
		]);
		expect(packages).toEqual(["@tanstack/react-router", "react"]);
	});

	it("returns an empty set when nothing came from node_modules", () => {
		expect(bundledPackages([["src/main.tsx"]])).toEqual([]);
	});
});

describe("recordedPackages", () => {
	const identity = [
		"[some earlier section]",
		"ignored",
		"",
		"[npm packages bundled into admin/dist]",
		"react",
		"@tanstack/react-query",
		"",
		"react-dom",
		"",
		"[a later section]",
		"not-a-package",
	].join("\n");

	it("reads only its own section, sorted and deduplicated", () => {
		expect(recordedPackages(identity)).toEqual(["@tanstack/react-query", "react", "react-dom"]);
	});

	it("distinguishes a missing section from an empty one", () => {
		expect(recordedPackages("[other]\nx\n")).toBeNull();
		expect(recordedPackages("[npm packages bundled into admin/dist]\n\n[next]\n")).toEqual([]);
	});
});

describe("comparePackages", () => {
	it("reports both directions", () => {
		const { added, removed } = comparePackages(["a", "b"], ["b", "c"]);
		expect(added).toEqual(["c"]);
		expect(removed).toEqual(["a"]);
	});

	it("reports nothing when the sets match", () => {
		expect(comparePackages(["a", "b"], ["a", "b"])).toEqual({ added: [], removed: [] });
		expect(formatDiff(["a"], ["a"])).toBe("");
	});

	it("formats a diff the way the failure prints it", () => {
		expect(formatDiff(["a", "b"], ["b", "c"])).toBe("-a\n+c");
	});
});
