import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MobileCardRow, type MobileCardField } from "../mobile-card";

interface Row {
	id: string;
	title: string;
	size: string;
	year: number;
}

const rows: Row[] = [
	{ id: "a", title: "Movie A", size: "4.2GB", year: 2026 },
	{ id: "b", title: "Movie B", size: "2.1GB", year: 2025 },
];

const fields: MobileCardField<Row>[] = [
	{ key: "title", label: "Title", render: (r) => r.title, primary: true },
	{ key: "size", label: "Size", render: (r) => r.size },
	{ key: "year", label: "Year", render: (r) => r.year },
];

describe("MobileCardRow", () => {
	it("renders the primary field as a title and the rest as key/value pairs", () => {
		render(<MobileCardRow rows={rows} fields={fields} />);

		// Primary title
		expect(screen.getByText("Movie A")).toBeInTheDocument();
		expect(screen.getByText("Movie B")).toBeInTheDocument();

		// Field labels and values (appear once per row)
		expect(screen.getAllByText("Size")).toHaveLength(2);
		expect(screen.getAllByText("4.2GB")).toHaveLength(1);
		expect(screen.getAllByText("Year")).toHaveLength(2);
		expect(screen.getAllByText("2026")).toHaveLength(1);
	});

	it("fires onRowClick when the card is tapped", async () => {
		const onRowClick = vi.fn();
		render(
			<MobileCardRow rows={rows} fields={fields} onRowClick={onRowClick} />,
		);

		await userEvent.click(screen.getByText("Movie A"));
		expect(onRowClick).toHaveBeenCalledTimes(1);
		expect(onRowClick).toHaveBeenCalledWith(rows[0]);
	});

	it("renders the actions slot per row", () => {
		render(
			<MobileCardRow
				rows={rows}
				fields={fields}
				actions={(r) => (
					<button type="button" onClick={() => undefined}>
						edit-{r.id}
					</button>
				)}
			/>,
		);

		expect(screen.getByText("edit-a")).toBeInTheDocument();
		expect(screen.getByText("edit-b")).toBeInTheDocument();
	});

	it("renders a non-interactive card when onRowClick is absent", () => {
		render(<MobileCardRow rows={rows} fields={fields} />);
		// No buttons wrapping the cards.
		expect(screen.queryAllByRole("button")).toHaveLength(0);
		expect(screen.getByText("Movie A")).toBeInTheDocument();
	});

	it("renders nothing when rows is empty", () => {
		const { container } = render(<MobileCardRow rows={[]} fields={fields} />);
		const cards = container.querySelector(".flex.flex-col.gap-2");
		expect(cards?.children).toHaveLength(0);
		expect(screen.queryByText("Size")).not.toBeInTheDocument();
	});

	it("renders a card without a title when no primary field is set", () => {
		const noPrimary: MobileCardField<Row>[] = fields.filter(
			(f) => f.key !== "title",
		);
		render(<MobileCardRow rows={rows} fields={noPrimary} />);
		// No title text rendered, but the key/value stack still is.
		expect(screen.queryByText("Movie A")).not.toBeInTheDocument();
		expect(screen.getAllByText("Size")).toHaveLength(2);
	});

	it("uses getRowId for stable keys and emits no duplicate-key warning", () => {
		const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
		render(<MobileCardRow rows={rows} fields={fields} getRowId={(r) => r.id} />);
		// No React duplicate-key warning should fire.
		const duplicateKeyCalls = errorSpy.mock.calls.filter((args) =>
			String(args[0] ?? "").includes("same key"),
		);
		expect(duplicateKeyCalls).toHaveLength(0);
		errorSpy.mockRestore();
	});
});
