import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { mkdir } from "node:fs/promises";
import { join } from "node:path";
import { $ } from "bun";
import { Core } from "../index.ts";
import { createUniqueTestDir, initializeTestProject, safeCleanup } from "./test-utils.ts";

let TEST_DIR: string;

describe("CLI search command", () => {
	const cliPath = join(process.cwd(), "src", "cli.ts");

	beforeEach(async () => {
		TEST_DIR = createUniqueTestDir("test-cli-search");
		await mkdir(TEST_DIR, { recursive: true });

		await $`git init -b main`.cwd(TEST_DIR).quiet();
		await $`git config user.name "Test User"`.cwd(TEST_DIR).quiet();
		await $`git config user.email test@example.com`.cwd(TEST_DIR).quiet();

		const core = new Core(TEST_DIR);
		await initializeTestProject(core, "Search Command Project");

		await core.createTask(
			{
				id: "task-1",
				title: "Central search integration",
				status: "To Do",
				assignee: ["@codex"],
				createdDate: "2025-09-18",
				labels: ["search"],
				dependencies: [],
				rawContent: "Implements central search module",
				description: "Implements central search module",
				modifiedFiles: ["src/web/App.tsx"],
			},
			false,
		);

		await core.createTask(
			{
				id: "task-2",
				title: "High priority follow-up",
				status: "In Progress",
				assignee: ["@codex"],
				createdDate: "2025-09-18",
				labels: ["search"],
				dependencies: [],
				rawContent: "Follow-up work",
				description: "Follow-up work",
				priority: "high",
				modifiedFiles: ["src/core/search-service.ts"],
			},
			false,
		);

		await core.filesystem.saveDocument({
			id: "doc-1",
			title: "Search Architecture Notes",
			type: "guide",
			createdDate: "2025-09-18",
			rawContent: "# Search Architecture Notes\nCentral search design",
		});

		await core.filesystem.saveDecision({
			id: "decision-1",
			title: "Adopt centralized search",
			date: "2025-09-18",
			status: "accepted",
			context: "Discussed search consolidation",
			decision: "Adopt shared Fuse index",
			consequences: "Unified search paths",
			rawContent: "## Context\nDiscussed search consolidation\n\n## Decision\nAdopt shared Fuse index",
		});
	});

	afterEach(async () => {
		await safeCleanup(TEST_DIR);
	});

	it("returns matching tasks, documents, and decisions in plain output", async () => {
		const result = await $`bun ${cliPath} search central --plain`.cwd(TEST_DIR).quiet();

		expect(result.exitCode).toBe(0);
		const stdout = result.stdout.toString();
		expect(stdout).toContain("Tasks:");
		expect(stdout).toContain("TASK-1 - Central search integration");
		expect(stdout).toContain("Documents:");
		expect(stdout).toContain("doc-1 - Search Architecture Notes");
		expect(stdout).toContain("Decisions:");
		expect(stdout).toContain("decision-1 - Adopt centralized search");
	});

	it("honors status and priority filters for task results", async () => {
		const statusResult = await $`bun ${cliPath} search follow-up --type task --status "In Progress" --plain`
			.cwd(TEST_DIR)
			.quiet();
		expect(statusResult.exitCode).toBe(0);
		const statusStdout = statusResult.stdout.toString();
		expect(statusStdout).toContain("TASK-2 - High priority follow-up");
		expect(statusStdout).not.toContain("TASK-1 - Central search integration");

		const priorityResult = await $`bun ${cliPath} search follow-up --type task --priority high --plain`
			.cwd(TEST_DIR)
			.quiet();
		expect(priorityResult.exitCode).toBe(0);
		const priorityStdout = priorityResult.stdout.toString();
		expect(priorityStdout).toContain("TASK-2 - High priority follow-up");
	});

	it("applies result limit", async () => {
		const result = await $`bun ${cliPath} search search --plain --limit 1`.cwd(TEST_DIR).quiet();
		expect(result.exitCode).toBe(0);
		const stdout = result.stdout.toString();
		const taskMatches = stdout.match(/TASK-\d+ -/g) || [];
		expect(taskMatches.length).toBeLessThanOrEqual(1);
	});

	it("rejects invalid result limits with a help hint", async () => {
		const result = await $`bun ${cliPath} search search --plain --limit 0`.cwd(TEST_DIR).nothrow().quiet();
		const output = result.stdout.toString() + result.stderr.toString();

		expect(result.exitCode).toBe(1);
		expect(output).toContain("--limit must be a positive integer (1 or greater).");
		expect(output).toContain("Try 'backlog search --help' for options.");
	});

	it("finds tasks by modified file path", async () => {
		const queryResult = await $`bun ${cliPath} search "src/web/App.tsx" --type task --plain`.cwd(TEST_DIR).quiet();
		expect(queryResult.exitCode).toBe(0);
		const queryStdout = queryResult.stdout.toString();
		expect(queryStdout).toContain("TASK-1 - Central search integration");

		const filterResult = await $`bun ${cliPath} search --modified-file core/search-service --plain`
			.cwd(TEST_DIR)
			.quiet();
		expect(filterResult.exitCode).toBe(0);
		const filterStdout = filterResult.stdout.toString();
		expect(filterStdout).toContain("TASK-2 - High priority follow-up");
		expect(filterStdout).not.toContain("TASK-1 - Central search integration");
		expect(filterStdout).not.toContain("Documents:");
	});
});
