// @vitest-environment jsdom
import "@testing-library/jest-dom/vitest";

import { cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, describe, expect, it, vi } from "vitest";

vi.mock("../../adapters/bestiary-cache.js", () => ({
	getCachedSources: vi.fn(),
	clearSource: vi.fn(),
	clearAll: vi.fn(),
}));

import * as bestiaryCache from "../../adapters/bestiary-cache.js";
import { SourceManager } from "../source-manager";

const mockGetCachedSources = vi.mocked(bestiaryCache.getCachedSources);
const mockClearSource = vi.mocked(bestiaryCache.clearSource);
const mockClearAll = vi.mocked(bestiaryCache.clearAll);

afterEach(() => {
	cleanup();
	vi.clearAllMocks();
});

describe("SourceManager", () => {
	it("shows 'No cached sources' empty state when no sources", async () => {
		mockGetCachedSources.mockResolvedValue([]);
		render(<SourceManager onCacheCleared={vi.fn()} />);
		await waitFor(() => {
			expect(screen.getByText("No cached sources")).toBeInTheDocument();
		});
	});

	it("lists cached sources with display name and creature count", async () => {
		mockGetCachedSources.mockResolvedValue([
			{
				sourceCode: "mm",
				displayName: "Monster Manual",
				creatureCount: 300,
				cachedAt: Date.now(),
			},
			{
				sourceCode: "vgm",
				displayName: "Volo's Guide",
				creatureCount: 100,
				cachedAt: Date.now(),
			},
		]);
		render(<SourceManager onCacheCleared={vi.fn()} />);
		await waitFor(() => {
			expect(screen.getByText("Monster Manual")).toBeInTheDocument();
		});
		expect(screen.getByText("300 creatures")).toBeInTheDocument();
		expect(screen.getByText("Volo's Guide")).toBeInTheDocument();
		expect(screen.getByText("100 creatures")).toBeInTheDocument();
	});

	it("Clear All button calls cache clear and onCacheCleared", async () => {
		const user = userEvent.setup();
		const onCacheCleared = vi.fn();
		mockGetCachedSources
			.mockResolvedValueOnce([
				{
					sourceCode: "mm",
					displayName: "Monster Manual",
					creatureCount: 300,
					cachedAt: Date.now(),
				},
			])
			.mockResolvedValue([]);
		mockClearAll.mockResolvedValue(undefined);
		render(<SourceManager onCacheCleared={onCacheCleared} />);

		await waitFor(() => {
			expect(screen.getByText("Monster Manual")).toBeInTheDocument();
		});

		await user.click(screen.getByRole("button", { name: "Clear All" }));
		await waitFor(() => {
			expect(mockClearAll).toHaveBeenCalled();
		});
		expect(onCacheCleared).toHaveBeenCalled();
	});

	it("individual source delete button calls clear for that source", async () => {
		const user = userEvent.setup();
		const onCacheCleared = vi.fn();
		mockGetCachedSources
			.mockResolvedValueOnce([
				{
					sourceCode: "mm",
					displayName: "Monster Manual",
					creatureCount: 300,
					cachedAt: Date.now(),
				},
				{
					sourceCode: "vgm",
					displayName: "Volo's Guide",
					creatureCount: 100,
					cachedAt: Date.now(),
				},
			])
			.mockResolvedValue([
				{
					sourceCode: "vgm",
					displayName: "Volo's Guide",
					creatureCount: 100,
					cachedAt: Date.now(),
				},
			]);
		mockClearSource.mockResolvedValue(undefined);

		render(<SourceManager onCacheCleared={onCacheCleared} />);
		await waitFor(() => {
			expect(screen.getByText("Monster Manual")).toBeInTheDocument();
		});

		await user.click(
			screen.getByRole("button", { name: "Remove Monster Manual" }),
		);
		await waitFor(() => {
			expect(mockClearSource).toHaveBeenCalledWith("mm");
		});
		expect(onCacheCleared).toHaveBeenCalled();
	});
});
