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

import { act, cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { createRef } from "react";
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
import { polyfillDialog } from "../../__tests__/polyfill-dialog.js";
import { AllProviders } from "../../__tests__/test-providers.js";
import {
	PlayerCharacterSection,
	type PlayerCharacterSectionHandle,
} from "../player-character-section.js";

const CREATE_FIRST_PC_REGEX = /create your first player character/i;

beforeAll(() => {
	polyfillDialog();
	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 renderSection() {
	const ref = createRef<PlayerCharacterSectionHandle>();
	const result = render(<PlayerCharacterSection ref={ref} />, {
		wrapper: AllProviders,
	});
	return { ...result, ref };
}

describe("PlayerCharacterSection", () => {
	it("openManagement ref handle opens the management dialog", async () => {
		const { ref } = renderSection();

		const handle = ref.current;
		if (!handle) throw new Error("ref not set");
		act(() => handle.openManagement());

		// Management dialog should now be open with its title visible
		await waitFor(() => {
			const dialogs = document.querySelectorAll("dialog");
			const managementDialog = Array.from(dialogs).find((d) =>
				d.textContent?.includes("Player Characters"),
			);
			expect(managementDialog).toHaveAttribute("open");
		});
	});

	it("creating a character from management opens create modal", async () => {
		const user = userEvent.setup();
		const { ref } = renderSection();

		const handle = ref.current;
		if (!handle) throw new Error("ref not set");
		act(() => handle.openManagement());

		await user.click(
			screen.getByRole("button", {
				name: CREATE_FIRST_PC_REGEX,
			}),
		);

		// Create modal should now be visible
		await waitFor(() => {
			expect(screen.getByPlaceholderText("Character name")).toBeInTheDocument();
		});
	});

	it("saving a new character and returning to management", async () => {
		const user = userEvent.setup();
		const { ref } = renderSection();

		const handle = ref.current;
		if (!handle) throw new Error("ref not set");
		act(() => handle.openManagement());

		await user.click(
			screen.getByRole("button", {
				name: CREATE_FIRST_PC_REGEX,
			}),
		);

		// Fill in the create form
		await user.type(screen.getByPlaceholderText("Character name"), "Aria");
		await user.type(screen.getByPlaceholderText("AC"), "16");
		await user.type(screen.getByPlaceholderText("Max HP"), "30");

		await user.click(screen.getByRole("button", { name: "Create" }));

		// Should return to management dialog showing the new character
		await waitFor(() => {
			expect(screen.getByText("Aria")).toBeInTheDocument();
		});
	});
});
