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

// Stub the composed widgets so the test exercises Dashboard's own behavior
// (shortcut CRUD) without rendering widgets or their data queries.
vi.mock("../../components/WidgetInstance", () => ({
	WidgetInstanceCard: () => <div data-testid="widget-stub" />,
}));
vi.mock("../../components/WidgetConfigDialog", () => ({
	WidgetConfigDialog: () => <div data-testid="widget-config-stub" />,
}));

const navigate = vi.fn();
vi.mock("react-router-dom", () => ({
	useNavigate: () => navigate,
}));

vi.mock("../../hooks/useSettings", () => ({
	useMonitoringSettings: () => ({ data: [] }),
}));
vi.mock("../../hooks/useWidgets", () => ({
	useWidgetInstances: () => ({ data: [] }),
	useWidgetReferences: () => ({ data: [] }),
	useDetachWidgetReference: () => ({ mutate: () => {} }),
}));
vi.mock("../../hooks/useServices", () => ({
	useServiceInstances: () => ({ data: [] }),
}));

const saveShortcutMutate = vi.fn().mockResolvedValue({});
const deleteShortcutMutate = vi.fn();

let shortcuts: DashboardShortcut[] = [];

vi.mock("../../hooks/useDashboard", () => ({
	useActivity: () => ({ data: undefined }),
	useDashboardShortcuts: () => ({ data: shortcuts }),
	useSaveDashboardShortcut: () => ({ mutateAsync: saveShortcutMutate }),
	useDeleteDashboardShortcut: () => ({ mutate: deleteShortcutMutate }),
}));

function websiteShortcut(
	overrides: Partial<DashboardShortcut> = {},
): DashboardShortcut {
	return {
		id: "s1",
		label: "Wiki",
		shortcut_type: "website",
		enabled: true,
		icon: "📚",
		url: "example.com",
		task_id: "",
		machine_id: "",
		user_id: "",
		notes: "Team wiki",
		created_at: 0,
		updated_at: 0,
		...overrides,
	} as DashboardShortcut;
}

beforeEach(() => {
	navigate.mockReset();
	saveShortcutMutate.mockClear();
	deleteShortcutMutate.mockClear();
	shortcuts = [];
});

describe("Dashboard", () => {
	it("shows the empty-state alert when there are no shortcuts", () => {
		render(<Dashboard />);
		expect(screen.getByText(/No shortcuts yet/)).toBeInTheDocument();
		expect(
			screen.getByRole("button", { name: "Add shortcut" }),
		).toBeInTheDocument();
	});

	it("renders a shortcut card and deletes it via the confirm dialog", async () => {
		shortcuts = [websiteShortcut()];
		render(<Dashboard />);

		expect(screen.getByText("Wiki")).toBeInTheDocument();

		// Open the delete confirm.
		await userEvent.click(screen.getByRole("button", { name: "Delete" }));
		expect(screen.getByText("Delete shortcut?")).toBeInTheDocument();

		// Confirm deletion -> delete mutation fires with the shortcut id.
		const dialogs = screen.getAllByRole("button", { name: "Delete" });
		// The card "Delete" plus the confirm "Delete"; confirm is the last one.
		await userEvent.click(dialogs[dialogs.length - 1]);
		expect(deleteShortcutMutate).toHaveBeenCalledTimes(1);
		expect(deleteShortcutMutate).toHaveBeenCalledWith("s1");
	});

	it("creates a shortcut via the dialog and saves it", async () => {
		render(<Dashboard />);

		await userEvent.click(screen.getByRole("button", { name: "Add shortcut" }));

		// Edit dialog opens in "New shortcut" mode.
		expect(screen.getByText("New shortcut")).toBeInTheDocument();

		// Fill the label and save.
		await userEvent.type(screen.getByLabelText("Label"), "Grafana");
		await userEvent.click(
			screen.getByRole("button", { name: "Save shortcut" }),
		);

		expect(saveShortcutMutate).toHaveBeenCalledTimes(1);
		const saved = saveShortcutMutate.mock.calls[0][0];
		expect(saved.label).toBe("Grafana");
		expect(saved.shortcut_type).toBe("website");
	});
});
