import { fireEvent, render, screen } from "@testing-library/react";
import type { KeyboardEvent } from "react";
import { describe, expect, it, vi } from "vitest";
import type { SelectionScreenProps } from "./SelectionScreen";
import { SelectionScreen } from "./SelectionScreen";

function makeProps(
	overrides: Partial<SelectionScreenProps> = {},
): SelectionScreenProps {
	return {
		knownProjects: [],
		onOpenProject: vi.fn(),
		onForgetProject: vi.fn(),
		pathInput: "",
		homeDir: null,
		onPathInputChange: vi.fn(),
		onPathInputKeyDown: vi.fn() as (
			event: KeyboardEvent<HTMLInputElement>,
		) => void,
		isOpening: false,
		suggestionTail: "",
		matchList: [],
		selectedMatch: -1,
		onSelectMatch: vi.fn(),
		onAcceptMatch: vi.fn(),
		onCloseSuggestions: vi.fn(),
		completionError: null,
		currentPartial: "",
		...overrides,
	};
}

describe("SelectionScreen", () => {
	it("renders the title and description", () => {
		render(<SelectionScreen {...makeProps()} />);
		expect(screen.getByText("Huskies")).toBeInTheDocument();
		expect(
			screen.getByText("Paste or complete a project path to start."),
		).toBeInTheDocument();
	});

	it("renders recent projects list when knownProjects is non-empty", () => {
		render(
			<SelectionScreen
				{...makeProps({ knownProjects: ["/Users/test/project"] })}
			/>,
		);
		expect(screen.getByText("Recent projects")).toBeInTheDocument();
	});

	it("does not render recent projects list when knownProjects is empty", () => {
		render(<SelectionScreen {...makeProps({ knownProjects: [] })} />);
		expect(screen.queryByText("Recent projects")).not.toBeInTheDocument();
	});

	it("calls onOpenProject when Open Project button is clicked", () => {
		const onOpenProject = vi.fn();
		render(
			<SelectionScreen
				{...makeProps({ pathInput: "/my/path", onOpenProject })}
			/>,
		);
		fireEvent.click(screen.getByText("Open Project"));
		expect(onOpenProject).toHaveBeenCalledWith("/my/path");
	});

	it("shows Opening... text and disables buttons when isOpening is true", () => {
		render(<SelectionScreen {...makeProps({ isOpening: true })} />);
		expect(screen.getByText("Opening...")).toBeInTheDocument();
		const buttons = screen.getAllByRole("button");
		for (const button of buttons) {
			if (
				button.textContent === "Opening..." ||
				button.textContent === "New Project"
			) {
				expect(button).toBeDisabled();
			}
		}
	});

	it("displays completion error when completionError is provided", () => {
		render(
			<SelectionScreen {...makeProps({ completionError: "Path not found" })} />,
		);
		expect(screen.getByText("Path not found")).toBeInTheDocument();
	});

	it("does not display error div when completionError is null", () => {
		const { container } = render(<SelectionScreen {...makeProps()} />);
		const errorDiv = container.querySelector('[style*="color: red"]');
		expect(errorDiv).toBeNull();
	});

	it("New Project button calls onPathInputChange with homeDir (trailing slash appended)", () => {
		const onPathInputChange = vi.fn();
		const onCloseSuggestions = vi.fn();
		render(
			<SelectionScreen
				{...makeProps({
					homeDir: "/Users/test",
					onPathInputChange,
					onCloseSuggestions,
				})}
			/>,
		);
		fireEvent.click(screen.getByText("New Project"));
		expect(onPathInputChange).toHaveBeenCalledWith("/Users/test/");
		expect(onCloseSuggestions).toHaveBeenCalled();
	});

	it("New Project button uses homeDir as-is when it already ends with /", () => {
		const onPathInputChange = vi.fn();
		const onCloseSuggestions = vi.fn();
		render(
			<SelectionScreen
				{...makeProps({
					homeDir: "/Users/test/",
					onPathInputChange,
					onCloseSuggestions,
				})}
			/>,
		);
		fireEvent.click(screen.getByText("New Project"));
		expect(onPathInputChange).toHaveBeenCalledWith("/Users/test/");
		expect(onCloseSuggestions).toHaveBeenCalled();
	});

	it("New Project button uses empty string when homeDir is null", () => {
		const onPathInputChange = vi.fn();
		render(
			<SelectionScreen {...makeProps({ homeDir: null, onPathInputChange })} />,
		);
		fireEvent.click(screen.getByText("New Project"));
		expect(onPathInputChange).toHaveBeenCalledWith("");
	});
});
