#!/usr/bin/env node
/**
 * check-test-imports.test.mjs — regression test for the test-import-drift guard.
 *
 * Verifies that check-test-imports.mjs correctly detects the anti-pattern:
 * a test file uses itemized `import { foo }` but references `bar` (not imported).
 *
 * All file paths are absolute to avoid resolution ambiguity when running from
 * different working directories.
 */

import { execSync } from "node:child_process";
import { writeFileSync, rmdirSync, mkdirSync, existsSync } from "node:fs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = fileURLToPath(new URL(".", import.meta.url)); // scripts/
const repoRoot = resolve(__dirname, ".."); // parent = repo root
const script = resolve(__dirname, "check-test-imports.mjs");
const tmpDir = resolve(__dirname, "tmp-check-test-imports");

// ── Helpers ───────────────────────────────────────────────────────────────────

/** Run the check script from the repo root, return {exitCode, stdout, stderr}. */
function run(args) {
	const cmd = ["node", "--", script, ...args].join(" ");
	try {
		const out = execSync(cmd, {
			cwd: repoRoot,
			encoding: "utf-8",
			stdio: ["pipe", "pipe", "pipe"],
		});
		return { exitCode: 0, stdout: out, stderr: "" };
	} catch (err) {
		return {
			exitCode: err.status ?? 1,
			stdout: (err.stdout || "").toString(),
			stderr: (err.stderr || "").toString(),
		};
	}
}

/** Create a temp test file, return absolute path. */
function makeTempFile(id, content) {
	try {
		mkdirSync(tmpDir, { recursive: true });
	} catch {
		/* */
	}
	const file = resolve(tmpDir, `regression-${id}.test.mjs`);
	writeFileSync(file, content);
	return file;
}

function cleanupTempDir() {
	try {
		rmdirSync(tmpDir);
	} catch {
		/* ignore */
	}
}

// ── Tests ─────────────────────────────────────────────────────────────────────

let passed = 0;
let failed = 0;

function assert(condition, message) {
	if (condition) {
		console.log(`  ✅  ${message}`);
		passed++;
	} else {
		console.error(`  ❌  ${message}`);
		failed++;
	}
}

console.log("check-test-imports regression tests\n");

// ── Test 1: Script is loadable and produces valid JSON ───────────────────────
// Use a real test file that exists under the repo root
const realFile = resolve(repoRoot, "tests/autonomous-solver.test.mjs");
if (!existsSync(realFile)) {
	console.error(`  ⚠️  Test file not found: ${realFile}`);
} else {
	const result1 = run([realFile, "--json"]);
	try {
		const parsed = JSON.parse(result1.stdout);
		assert(
			typeof parsed.count === "number",
			`Valid JSON with count: ${parsed.count}`,
		);
	} catch {
		assert(false, `Script should produce valid JSON output`);
	}
}

// ── Test 2: Detects undeclared identifier in anti-pattern file ───────────────
console.log("\n[2] Detects undeclared identifier in anti-pattern file");
const file2 = makeTempFile(
	"regression-02",
	`
// Regression test — generated by check-test-imports.test.mjs
// DO NOT COMMIT
import { describe, it, expect } from "vitest";
import { fn1, fn2, fn3, fn4, fn5, fn6 } from "./fixture.mjs";

describe("test", () => {
	it("uses undeclaredFn", () => {
		undeclaredFn();
	});
});
`,
);
const result2 = run([file2, "--json"]);
try {
	const parsed = JSON.parse(result2.stdout);
	assert(
		parsed.count > 0,
		`Drift detected in anti-pattern file (count: ${parsed.count})`,
	);
	assert(
		result2.exitCode === 1,
		`Exit code 1 when drift present (got: ${result2.exitCode})`,
	);
} catch {
	assert(false, `Should not throw when drift is detected`);
}

// ── Test 3: Clean file with namespace import passes ─────────────────────────
console.log("\n[3] Clean file with namespace import + local vars passes");
const file3 = makeTempFile(
	"regression-03",
	`
// Clean: namespace import + only local variables
// DO NOT COMMIT
import { describe, it, expect } from "vitest";
import * as Fixtures from "./fixture.mjs";

const myLocalVar = Fixtures.fn1();

describe("test", () => {
	it("uses Fixtures methods", () => {
		expect(myLocalVar).toBeDefined();
	});
});
`,
);
const result3 = run([file3, "--json"]);
try {
	const parsed = JSON.parse(result3.stdout);
	assert(parsed.count === 0, `Clean file: count ${parsed.count}`);
} catch {
	assert(false, `Script should not throw on clean file`);
}

// ── Test 4: Local const/let declarations not flagged ───────────────────────
console.log("\n[4] Local const/let declarations not flagged");
const file4 = makeTempFile(
	"regression-04",
	`
// Local variable declarations should not be flagged
// DO NOT COMMIT
import { describe, it, expect } from "vitest";
import { foo } from "./fixture.mjs";

const myLocalVar = foo();
const anotherLocal = foo();

describe("test", () => {
	it("uses local variables", () => {
		expect(myLocalVar).toBeDefined();
	});
});
`,
);
const result4 = run([file4, "--json"]);
try {
	const parsed = JSON.parse(result4.stdout);
	assert(
		parsed.count === 0,
		`Local variables not flagged (count: ${parsed.count})`,
	);
} catch {
	assert(false, `Should not throw on clean file`);
}

// ── Test 5: Short lowercase variables not flagged ───────────────────────────
console.log("\n[5] Short lowercase variables not flagged");
const file5 = makeTempFile(
	"regression-05",
	`
// Short lowercase vars like i, fn are common test locals
// DO NOT COMMIT
import { describe, it, expect } from "vitest";
import { fn } from "./fixture.mjs";

describe("test", () => {
	it("works with short vars", () => {
		const i = fn();
		const j = i + 1;
		expect(j).toBeGreaterThan(0);
	});
});
`,
);
const result5 = run([file5, "--json"]);
try {
	const parsed = JSON.parse(result5.stdout);
	assert(
		parsed.count === 0,
		`Short lowercase vars not flagged (count: ${parsed.count})`,
	);
} catch {
	assert(false, `Should not throw on clean file`);
}

// ── Summary ─────────────────────────────────────────────────────────────────

console.log(`\n${"-".repeat(50)}`);
console.log(`Results: ${passed} passed, ${failed} failed`);
cleanupTempDir();
process.exit(failed > 0 ? 1 : 0);
