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

import { type PlayerCharacter, playerCharacterId } from "@initiative/domain";
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 { polyfillDialog } from "../../__tests__/polyfill-dialog.js";

afterEach(cleanup);

const CREATE_FIRST_PC_REGEX = /create your first player character/i;
const LEVEL_REGEX = /^Lv /;

import { PlayerManagement } from "../player-management.js";

beforeAll(() => {
	polyfillDialog();
});

const PC_WARRIOR: PlayerCharacter = {
	id: playerCharacterId("pc-1"),
	name: "Thorin",
	ac: 18,
	maxHp: 45,
	color: "red",
	icon: "sword",
};

const PC_WIZARD: PlayerCharacter = {
	id: playerCharacterId("pc-2"),
	name: "Gandalf",
	ac: 12,
	maxHp: 30,
	color: "blue",
	icon: "wand",
	level: 10,
};

function renderManagement(
	overrides: Partial<Parameters<typeof PlayerManagement>[0]> = {},
) {
	const props = {
		open: true,
		onClose: vi.fn(),
		characters: [] as readonly PlayerCharacter[],
		onEdit: vi.fn(),
		onDelete: vi.fn(),
		onCreate: vi.fn(),
		...overrides,
	};
	return { ...render(<PlayerManagement {...props} />), props };
}

describe("PlayerManagement", () => {
	it("shows empty state when no characters", () => {
		renderManagement();
		expect(screen.getByText("No player characters yet")).toBeInTheDocument();
	});

	it("shows create button in empty state that calls onCreate", async () => {
		const user = userEvent.setup();
		const { props } = renderManagement();

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

	it("renders each character with name, AC, HP", () => {
		renderManagement({ characters: [PC_WARRIOR, PC_WIZARD] });
		expect(screen.getByText("Thorin")).toBeInTheDocument();
		expect(screen.getByText("Gandalf")).toBeInTheDocument();
		expect(screen.getByText("AC 18")).toBeInTheDocument();
		expect(screen.getByText("HP 45")).toBeInTheDocument();
		expect(screen.getByText("AC 12")).toBeInTheDocument();
		expect(screen.getByText("HP 30")).toBeInTheDocument();
	});

	it("shows level when present, omits when undefined", () => {
		renderManagement({ characters: [PC_WARRIOR, PC_WIZARD] });
		expect(screen.getByText("Lv 10")).toBeInTheDocument();
		// Thorin has no level — there should be only one "Lv" text
		expect(screen.queryAllByText(LEVEL_REGEX)).toHaveLength(1);
	});

	it("edit button calls onEdit with the character", async () => {
		const user = userEvent.setup();
		const { props } = renderManagement({ characters: [PC_WARRIOR] });

		await user.click(screen.getByRole("button", { name: "Edit" }));
		expect(props.onEdit).toHaveBeenCalledWith(PC_WARRIOR);
	});

	it("delete button calls onDelete after confirmation", async () => {
		const user = userEvent.setup();
		const { props } = renderManagement({ characters: [PC_WARRIOR] });

		const deleteBtn = screen.getByRole("button", {
			name: "Delete player character",
		});
		await user.click(deleteBtn);
		const confirmBtn = screen.getByRole("button", {
			name: "Confirm delete player character",
		});
		await user.click(confirmBtn);
		expect(props.onDelete).toHaveBeenCalledWith(PC_WARRIOR.id);
	});

	it("add button calls onCreate", async () => {
		const user = userEvent.setup();
		const { props } = renderManagement({ characters: [PC_WARRIOR] });

		await user.click(screen.getByRole("button", { name: "Add" }));
		expect(props.onCreate).toHaveBeenCalled();
	});
});
