import {
	existsSync,
	mkdirSync,
	mkdtempSync,
	readFileSync,
	rmSync,
	writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
	appendPromptHistory,
	readPromptHistory,
} from "../ui/prompt-history.js";

describe("prompt history", () => {
	let oldHome;
	let oldSkipPromptHistory;
	let homeDir;
	let projectDir;

	beforeEach(() => {
		oldHome = process.env.HOME;
		oldSkipPromptHistory = process.env.SF_SKIP_PROMPT_HISTORY;
		homeDir = mkdtempSync(join(tmpdir(), "sf-home-"));
		projectDir = mkdtempSync(join(tmpdir(), "sf-project-"));
		process.env.HOME = homeDir;
		delete process.env.SF_SKIP_PROMPT_HISTORY;
	});

	afterEach(() => {
		process.env.HOME = oldHome;
		if (oldSkipPromptHistory === undefined) {
			delete process.env.SF_SKIP_PROMPT_HISTORY;
		} else {
			process.env.SF_SKIP_PROMPT_HISTORY = oldSkipPromptHistory;
		}
		rmSync(homeDir, { recursive: true, force: true });
		rmSync(projectDir, { recursive: true, force: true });
	});

	it("appendPromptHistory_when_projectPathProvided_persists_tagged_global_entry", () => {
		appendPromptHistory("first prompt", projectDir, "session-1");

		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");

		expect(existsSync(globalPath)).toBe(true);
		expect(
			readFileSync(globalPath, "utf-8")
				.trim()
				.split(/\r?\n/)
				.map((line) => JSON.parse(line)),
		).toMatchObject([
			{
				version: 1,
				prompt: "first prompt",
				projectRoot: projectDir,
				sessionId: "session-1",
			},
		]);
	});

	it("readPromptHistory_when_history_contains_multiple_projects_returns_current_project_only", () => {
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");
		mkdirSync(join(homeDir, ".sf", "agent"), { recursive: true });
		writeFileSync(
			globalPath,
			[
				JSON.stringify({
					version: 1,
					prompt: "shared",
					projectRoot: projectDir,
					sessionId: "session-1",
					timestamp: 1,
				}),
				JSON.stringify({
					version: 1,
					prompt: "project",
					projectRoot: projectDir,
					sessionId: "session-1",
					timestamp: 2,
				}),
				JSON.stringify({
					version: 1,
					prompt: "other project",
					projectRoot: join(projectDir, "other"),
					sessionId: "session-2",
					timestamp: 3,
				}),
			].join("\n") + "\n",
			"utf-8",
		);

		expect(readPromptHistory(projectDir)).toEqual(["project", "shared"]);
	});

	it("readPromptHistory_when_project_history_has_duplicates_returns_newest_unique_prompts", () => {
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");
		mkdirSync(join(homeDir, ".sf", "agent"), { recursive: true });
		writeFileSync(
			globalPath,
			[
				JSON.stringify({
					version: 1,
					prompt: "repeat",
					projectRoot: projectDir,
					sessionId: "session-1",
					timestamp: 1,
				}),
				JSON.stringify({
					version: 1,
					prompt: "newest",
					projectRoot: projectDir,
					sessionId: "session-1",
					timestamp: 2,
				}),
				JSON.stringify({
					version: 1,
					prompt: "repeat",
					projectRoot: projectDir,
					sessionId: "session-2",
					timestamp: 3,
				}),
			].join("\n") + "\n",
			"utf-8",
		);

		expect(readPromptHistory(projectDir)).toEqual(["repeat", "newest"]);
	});

	it("readPromptHistory_when_jsonl_contains_malformed_line_skips_that_line", () => {
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");
		mkdirSync(join(homeDir, ".sf", "agent"), { recursive: true });
		writeFileSync(
			globalPath,
			[
				"{not json",
				JSON.stringify({
					version: 1,
					prompt: "valid",
					projectRoot: projectDir,
					sessionId: "session-1",
					timestamp: 1,
				}),
			].join("\n") + "\n",
			"utf-8",
		);

		expect(readPromptHistory(projectDir)).toEqual(["valid"]);
	});

	it("readPromptHistory_when_legacy_untagged_history_exists_ignores_it", () => {
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.json");
		mkdirSync(join(homeDir, ".sf", "agent"), { recursive: true });
		writeFileSync(
			globalPath,
			JSON.stringify({ version: 1, history: ["global leak"] }, null, 2) + "\n",
			"utf-8",
		);

		expect(readPromptHistory(projectDir)).toEqual([]);
	});

	it("appendPromptHistory_when_projectPathMissing_does_not_persist_history", () => {
		appendPromptHistory("global leak");
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");

		expect(existsSync(globalPath)).toBe(false);
		expect(readPromptHistory()).toEqual([]);
	});

	it("appendPromptHistory_when_skip_env_enabled_does_not_persist_history", () => {
		process.env.SF_SKIP_PROMPT_HISTORY = "1";

		appendPromptHistory("secret prompt", projectDir);
		const globalPath = join(homeDir, ".sf", "agent", "prompt-history.jsonl");

		expect(existsSync(globalPath)).toBe(false);
	});
});
