import assert from "node:assert/strict";
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, test } from "vitest";
// Import preferences.js so that _initPrefsLoader is called and the circular dep lazy-loader is wired up.
import "../preferences.js";
import {
	isModelInEnabledList,
	resolveModelWithFallbacksForUnit,
} from "../preferences-models.js";

const originalCwd = process.cwd();
const originalEnv = { ...process.env };
const tmpDirs = [];

afterEach(() => {
	process.chdir(originalCwd);
	process.env = { ...originalEnv };
	while (tmpDirs.length > 0) {
		rmSync(tmpDirs.pop(), { recursive: true, force: true });
	}
});

function makePreferencesProject(projectPreferences, projectSettings) {
	const root = mkdtempSync(join(tmpdir(), "sf-preferences-models-"));
	tmpDirs.push(root);
	const home = join(root, "home");
	const project = join(root, "project");
	mkdirSync(join(home, ".sf", "agent"), { recursive: true });
	mkdirSync(join(project, ".sf"), { recursive: true });
	writeFileSync(
		join(project, ".sf", "preferences.yaml"),
		projectPreferences,
		"utf-8",
	);
	if (projectSettings) {
		writeFileSync(
			join(project, ".sf", "settings.json"),
			JSON.stringify(projectSettings, null, 2),
			"utf-8",
		);
	}
	process.env.HOME = home;
	process.env.SF_HOME = join(home, ".sf");
	process.chdir(project);
	return project;
}

function writeLegacyGlobalPreferences(project, content) {
	const sfHome = join(project, "..", "home", ".sf");
	writeFileSync(join(sfHome, "preferences.md"), content, "utf-8");
}

describe("preferences model resolution", () => {
	test("resolveModelWithFallbacksForUnit_when_google_env_auth_is_default_off_skips_google_auto_benchmark_candidates", () => {
		makePreferencesProject(
			["version: 1", "allowed_providers:", "  - google", "models: {}", ""].join(
				"\n",
			),
		);
		process.env.GEMINI_API_KEY = "test-google-key";

		const result = resolveModelWithFallbacksForUnit("plan-milestone");

		assert.equal(result, undefined);
	});

	test("resolveModelWithFallbacksForUnit_when_global_yaml_missing_reads_legacy_global_preferences_md", () => {
		const project = makePreferencesProject(
			["version: 1", "models: {}", ""].join("\n"),
		);
		writeLegacyGlobalPreferences(
			project,
			[
				"---",
				"version: 1",
				"models:",
				"  execution: kimi-coding/kimi-k2.6",
				"---",
				"",
				"# Global SF Preferences",
				"",
			].join("\n"),
		);

		const result = resolveModelWithFallbacksForUnit("execute-task");

		assert.deepEqual(result, {
			primary: "kimi-coding/kimi-k2.6",
			fallbacks: [],
		});
	});

	test("resolveModelWithFallbacksForUnit_when_rewrite_docs_has_no_validation_model_uses_execution_model", () => {
		makePreferencesProject(
			[
				"version: 1",
				"models:",
				"  planning: minimax/MiniMax-M2.7",
				"  execution: kimi-coding/kimi-k2.6",
				"",
			].join("\n"),
		);

		const result = resolveModelWithFallbacksForUnit("rewrite-docs");

		assert.deepEqual(result, {
			primary: "kimi-coding/kimi-k2.6",
			fallbacks: [],
		});
	});

	test("isModelInEnabledList_when_list_empty_allows_any_model", () => {
		assert.equal(isModelInEnabledList("kimi-coding", "kimi-k2.6", []), true);
		assert.equal(
			isModelInEnabledList("kimi-coding", "kimi-k2.6", undefined),
			true,
		);
	});

	test("isModelInEnabledList_when_exact_or_provider_wildcard_matches_returns_true", () => {
		assert.equal(
			isModelInEnabledList("kimi-coding", "kimi-k2.6", [
				"openai/gpt-5.2",
				"kimi-coding/kimi-k2.6",
			]),
			true,
		);
		assert.equal(
			isModelInEnabledList("kimi-coding", "kimi-k2.6", ["kimi-coding/*"]),
			true,
		);
	});

	test("isModelInEnabledList_when_no_pattern_matches_returns_false", () => {
		assert.equal(
			isModelInEnabledList("kimi-coding", "kimi-k2.6", ["openai/*"]),
			false,
		);
	});
});
