import { describe, it, expect, vi } from "vitest";
import { useState } from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type { ColumnDef } from "@tanstack/react-table";
import { DataTable } from "../data-table";

interface Row {
	id: string;
	name: string;
	role: string;
}

const rows: Row[] = [
	{ id: "1", name: "Alice", role: "Admin" },
	{ id: "2", name: "Bob", role: "Editor" },
	{ id: "3", name: "Carol", role: "Viewer" },
];

const columns: ColumnDef<Row>[] = [
	{
		accessorKey: "name",
		header: () => "Name",
		cell: ({ row }) => row.original.name,
	},
	{
		accessorKey: "role",
		header: () => "Role",
		cell: ({ row }) => row.original.role,
	},
];

/** Wrapper so the DataTable's controlled state can update during interaction. */
function Harness({
	onRowClick,
	initialSelection = {},
}: {
	onRowClick?: (row: Row) => void;
	initialSelection?: Record<string, boolean>;
}) {
	const [selection, setSelection] =
		useState<Record<string, boolean>>(initialSelection);
	const [visibility, setVisibility] = useState<Record<string, boolean>>({});
	return (
		<DataTable
			columns={columns}
			data={rows}
			getRowId={(row) => row.id}
			enableRowSelection
			rowSelection={selection}
			onRowSelectionChange={setSelection}
			onRowClick={onRowClick}
			enableColumnVisibilityToggle
			columnVisibility={visibility}
			onColumnVisibilityChange={setVisibility}
		/>
	);
}

describe("DataTable (slice 7a — TanStack wrapper)", () => {
	it("renders the column headers and rows", () => {
		render(<Harness />);
		expect(screen.getByText("Name")).toBeInTheDocument();
		expect(screen.getByText("Role")).toBeInTheDocument();
		expect(screen.getByText("Alice")).toBeInTheDocument();
		expect(screen.getByText("Carol")).toBeInTheDocument();
	});

	it("toggles row selection via the per-row checkbox and reflects state", async () => {
		render(<Harness />);
		// Header select-all checkbox + one per-row checkbox exist before rows.
		expect(screen.getAllByRole("checkbox", { name: "Select row" }).length).toBe(
			rows.length,
		);

		const aliceCheckbox = screen.getAllByRole("checkbox", {
			name: "Select row",
		})[0];
		await userEvent.click(aliceCheckbox);
		expect(aliceCheckbox).toBeChecked();

		// Toggling again un-selects (controlled membership flips).
		await userEvent.click(aliceCheckbox);
		expect(aliceCheckbox).not.toBeChecked();
	});

	it("selects all page rows via the header select-all checkbox", async () => {
		render(<Harness />);
		const selectAll = screen.getByRole("checkbox", {
			name: "Select all rows on this page",
		});
		await userEvent.click(selectAll);
		for (const cb of screen.getAllByRole("checkbox", { name: "Select row" })) {
			expect(cb).toBeChecked();
		}
		await userEvent.click(selectAll);
		for (const cb of screen.getAllByRole("checkbox", { name: "Select row" })) {
			expect(cb).not.toBeChecked();
		}
	});

	it("toggles column visibility via the Columns dropdown (column disappears)", async () => {
		render(<Harness />);

		// Role column header present initially.
		expect(screen.getByText("Role")).toBeInTheDocument();

		await userEvent.click(screen.getByRole("button", { name: /Columns/ }));
		await userEvent.click(
			screen.getByRole("menuitemcheckbox", { name: "role" }),
		);

		// Role header + all role cells vanish from the table.
		expect(screen.queryByText("Role")).toBeNull();
		expect(screen.queryByText("Admin")).toBeNull();
		expect(screen.queryByText("Viewer")).toBeNull();
		// Name column is unaffected.
		expect(screen.getByText("Name")).toBeInTheDocument();
		expect(screen.getByText("Alice")).toBeInTheDocument();
	});

	it("fires onRowClick with row.original when a row body is clicked", async () => {
		const onRowClick = vi.fn();
		render(<Harness onRowClick={onRowClick} />);

		await userEvent.click(screen.getByText("Bob"));
		expect(onRowClick).toHaveBeenCalledTimes(1);
		expect(onRowClick).toHaveBeenCalledWith(
			expect.objectContaining({ id: "2", name: "Bob", role: "Editor" }),
		);
	});

	it("does NOT fire onRowClick when the selection checkbox is toggled", async () => {
		const onRowClick = vi.fn();
		render(<Harness onRowClick={onRowClick} />);

		const firstCheckbox = screen.getAllByRole("checkbox", {
			name: "Select row",
		})[0];
		await userEvent.click(firstCheckbox);
		expect(onRowClick).not.toHaveBeenCalled();
	});

	it("renders the empty message when data is empty", () => {
		render(
			<DataTable
				columns={columns}
				data={[]}
				emptyMessage="No files in this directory."
			/>,
		);
		expect(screen.getByText("No files in this directory.")).toBeInTheDocument();
	});

	it("renders client pagination controls when enabled", () => {
		render(
			<DataTable
				columns={columns}
				data={rows}
				enablePagination
				pageSizeOptions={[2, 10]}
			/>,
		);
		expect(screen.getByText(/Page 1 of/)).toBeInTheDocument();
		expect(
			screen.getByRole("button", { name: "Previous page" }),
		).toBeDisabled();
		expect(screen.getByRole("button", { name: "Next page" })).toBeEnabled();
	});

	it("renders the manual pagination total when rowCount is supplied", () => {
		render(
			<DataTable
				columns={columns}
				data={rows.slice(0, 2)}
				enablePagination
				manualPagination
				rowCount={42}
				pagination={{ pageIndex: 0, pageSize: 2 }}
			/>,
		);
		expect(screen.getByText("42 rows")).toBeInTheDocument();
		expect(screen.getByText(/Page 1 of 21/)).toBeInTheDocument();
	});
});
