import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { FileBrowser } from "../FileBrowser.impl";
import type { DirectoryListing, MonitoringMachine } from "../../types";

// usePersistentState (browserState) reads/writes localStorage; clear between tests
// so the selectedPath / currentDir state never leaks across cases.
beforeEach(() => {
	window.localStorage.clear();
});

function machineFixture(
	overrides: Partial<MonitoringMachine> = {},
): MonitoringMachine {
	return {
		id: "local",
		name: "Local",
		mode: "local",
		enabled: true,
		services: ["files", "monitoring"],
		host: "",
		port: 22,
		username: "",
		key_directory: "",
		key_name: "",
		ssh_key_id: "",
		ssh_private_key_set: false,
		ssh_private_key_passphrase_set: false,
		password_set: false,
		media_root: "",
		path_prefix: "",
		jellyfin_url: "",
		jellyfin_user_id: "",
		jellyfin_api_key_set: false,
		jellyseerr_url: "",
		jellyseerr_api_key_set: false,
		notes: "",
		...overrides,
	};
}

function listingFixture(
	entries: {
		name: string;
		type: string;
		size: number;
		mtime: number;
	}[],
): DirectoryListing {
	return { path: "/", entries, count: entries.length };
}

let listing: DirectoryListing;
let machines: MonitoringMachine[];

vi.mock("react-router-dom", () => ({
	useSearchParams: () => [new URLSearchParams(), vi.fn()],
	useNavigate: () => vi.fn(),
}));

vi.mock("../../hooks/useFiles", () => ({
	useDirectoryListing: () => ({
		data: listing,
		isLoading: false,
		error: null,
		refetch: vi.fn(),
	}),
	useFfprobe: () => ({ data: undefined, isLoading: false, error: null }),
	useJobTemplates: () => ({ data: [] }),
	useRunJob: () => ({ isPending: false, mutate: vi.fn(), data: undefined }),
}));

vi.mock("../../hooks/useSettings", () => ({
	useMonitoringSettings: () => ({ data: machines }),
}));

beforeEach(() => {
	machines = [machineFixture()];
	listing = listingFixture([
		{ name: "movies", type: "d", size: 0, mtime: 1_700_000_000 },
		{ name: "video.mkv", type: "f", size: 1_500_000_000, mtime: 1_700_000_000 },
		{ name: "notes.txt", type: "f", size: 12, mtime: 1_700_000_000 },
	]);
});

describe("FileBrowser (slice 7a — TanStack DataTable parity)", () => {
	it("renders the 5 locked columns (type/name/ext/size/modified)", () => {
		render(<FileBrowser />);

		const headers = screen
			.getAllByRole("columnheader")
			.map((h) => h.textContent);
		// The leading selection column header is empty (checkbox); the 5 data
		// columns are Type, Name, Ext, Size, Modified in that order.
		expect(headers).toEqual(
			expect.arrayContaining(["Type", "Name", "Ext", "Size", "Modified"]),
		);
		expect(headers.filter((h) => h === "Type").length).toBe(1);
		expect(headers.filter((h) => h === "Modified").length).toBe(1);
	});

	it("clicking a file row selects it for ffprobe preview (Media info)", async () => {
		render(<FileBrowser />);

		// The selected-file path surfaces in the Browser status caption once chosen.
		expect(screen.queryByText(/Selected: \/video\.mkv/)).toBeNull();

		await userEvent.click(screen.getByText("video.mkv"));
		expect(screen.getByText(/Selected: \/video\.mkv/)).toBeInTheDocument();

		// A recognized video file enters the ffprobe branch; with empty ffprobe
		// data it shows the "No ffprobe data available." status (proving the
		// selected file routed into the Media info preview flow).
		expect(screen.getByText("No ffprobe data available.")).toBeInTheDocument();
	});

	it("clicking a directory row navigates into it (no ffprobe selection)", async () => {
		render(<FileBrowser />);

		await userEvent.click(screen.getByText("movies"));
		// After navigating into /movies, the status caption shows the new cwd and
		// NO "Selected:" segment (directories are opened, not selected for preview).
		expect(screen.getByText(/Current: \/movies\b/)).toBeInTheDocument();
		expect(screen.queryByText(/Selected:/)).toBeNull();
	});
});
