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

import { cleanup, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import { AllProviders } from "../../__tests__/test-providers.js";
import { ActionBar } from "../action-bar.js";

// Mock persistence — no localStorage interaction
vi.mock("../../persistence/encounter-storage.js", () => ({
	loadEncounter: () => null,
	saveEncounter: () => {},
}));

vi.mock("../../persistence/player-character-storage.js", () => ({
	loadPlayerCharacters: () => [],
	savePlayerCharacters: () => {},
}));

// Mock bestiary — no IndexedDB or JSON index
vi.mock("../../adapters/bestiary-cache.js", () => ({
	loadAllCachedCreatures: () => Promise.resolve(new Map()),
	isSourceCached: () => Promise.resolve(false),
	cacheSource: () => Promise.resolve(),
	getCachedSources: () => Promise.resolve([]),
	clearSource: () => Promise.resolve(),
	clearAll: () => Promise.resolve(),
}));

vi.mock("../../adapters/bestiary-index-adapter.js", () => ({
	loadBestiaryIndex: () => ({ sources: {}, creatures: [] }),
	getAllSourceCodes: () => [],
	getDefaultFetchUrl: () => "",
	getSourceDisplayName: (code: string) => code,
}));

// DOM API stubs — jsdom doesn't implement these
beforeAll(() => {
	Object.defineProperty(globalThis, "matchMedia", {
		writable: true,
		value: vi.fn().mockImplementation((query: string) => ({
			matches: false,
			media: query,
			onchange: null,
			addListener: vi.fn(),
			removeListener: vi.fn(),
			addEventListener: vi.fn(),
			removeEventListener: vi.fn(),
			dispatchEvent: vi.fn(),
		})),
	});
});

afterEach(cleanup);

function renderBar(props: Partial<Parameters<typeof ActionBar>[0]> = {}) {
	return render(<ActionBar {...props} />, { wrapper: AllProviders });
}

describe("ActionBar", () => {
	it("renders input with placeholder '+ Add combatants'", () => {
		renderBar();
		expect(screen.getByPlaceholderText("+ Add combatants")).toBeInTheDocument();
	});

	it("submitting with a name adds a combatant", async () => {
		const user = userEvent.setup();
		renderBar();
		const input = screen.getByPlaceholderText("+ Add combatants");
		await user.type(input, "Goblin");
		// The Add button appears when name >= 2 chars and no suggestions
		const addButton = screen.getByRole("button", { name: "Add" });
		await user.click(addButton);
		// Input is cleared after adding (context handles the state)
		expect(input).toHaveValue("");
	});

	it("submitting with empty name does nothing", async () => {
		const user = userEvent.setup();
		renderBar();
		// Submit the form directly (Enter on empty input)
		const input = screen.getByPlaceholderText("+ Add combatants");
		await user.type(input, "{Enter}");
		// Input stays empty, no error
		expect(input).toHaveValue("");
	});

	it("shows custom fields (Init, AC, MaxHP) when name >= 2 chars and no bestiary suggestions", async () => {
		const user = userEvent.setup();
		renderBar();
		const input = screen.getByPlaceholderText("+ Add combatants");
		await user.type(input, "Go");
		expect(screen.getByPlaceholderText("Init")).toBeInTheDocument();
		expect(screen.getByPlaceholderText("AC")).toBeInTheDocument();
		expect(screen.getByPlaceholderText("MaxHP")).toBeInTheDocument();
	});

	it("shows Add button when name >= 2 chars and no suggestions", async () => {
		const user = userEvent.setup();
		renderBar();
		const input = screen.getByPlaceholderText("+ Add combatants");
		await user.type(input, "Go");
		expect(screen.getByRole("button", { name: "Add" })).toBeInTheDocument();
	});

	it("does not show roll all initiative button when no creature combatants", () => {
		renderBar();
		expect(
			screen.queryByRole("button", { name: "Roll all initiative" }),
		).not.toBeInTheDocument();
	});

	it("shows overflow menu items", () => {
		renderBar({ onManagePlayers: vi.fn() });
		// The overflow menu should be present (it contains Player Characters etc.)
		expect(
			screen.getByRole("button", { name: "More actions" }),
		).toBeInTheDocument();
	});
});
