// @vitest-environment jsdom
import { playerCharacterId } from "@initiative/domain";
import { act, renderHook } from "@testing-library/react";
import type { ReactNode } from "react";
import { beforeAll, describe, expect, it, vi } from "vitest";
import { createTestAdapters } from "../../__tests__/adapters/in-memory-adapters.js";
import { AllProviders } from "../../__tests__/test-providers.js";
import { usePlayerCharacters } from "../use-player-characters.js";

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(),
		})),
	});
});

function wrapper({ children }: { children: ReactNode }) {
	return <AllProviders>{children}</AllProviders>;
}

describe("usePlayerCharacters", () => {
	it("initializes with characters from persistence", () => {
		const stored = [
			{
				id: playerCharacterId("pc-1"),
				name: "Aria",
				ac: 16,
				maxHp: 30,
				color: undefined,
				icon: undefined,
			},
		];
		const adapters = createTestAdapters({ playerCharacters: stored });

		const { result } = renderHook(() => usePlayerCharacters(), {
			wrapper: ({ children }: { children: ReactNode }) => (
				<AllProviders adapters={adapters}>{children}</AllProviders>
			),
		});

		expect(result.current.characters).toEqual(stored);
	});

	it("createCharacter adds a character and persists", () => {
		const { result } = renderHook(() => usePlayerCharacters(), { wrapper });

		act(() => {
			result.current.createCharacter(
				"Vex",
				15,
				28,
				undefined,
				undefined,
				undefined,
			);
		});

		expect(result.current.characters).toHaveLength(1);
		expect(result.current.characters[0].name).toBe("Vex");
		expect(result.current.characters[0].ac).toBe(15);
		expect(result.current.characters[0].maxHp).toBe(28);
	});

	it("createCharacter returns domain error for empty name", () => {
		const { result } = renderHook(() => usePlayerCharacters(), { wrapper });

		let error: unknown;
		act(() => {
			error = result.current.createCharacter(
				"",
				15,
				28,
				undefined,
				undefined,
				undefined,
			);
		});

		expect(error).toMatchObject({ kind: "domain-error" });
		expect(result.current.characters).toHaveLength(0);
	});

	it("editCharacter updates character and persists", () => {
		const { result } = renderHook(() => usePlayerCharacters(), { wrapper });

		act(() => {
			result.current.createCharacter(
				"Vex",
				15,
				28,
				undefined,
				undefined,
				undefined,
			);
		});

		const id = result.current.characters[0].id;

		act(() => {
			result.current.editCharacter(id, { name: "Vex'ahlia" });
		});

		expect(result.current.characters[0].name).toBe("Vex'ahlia");
	});

	it("deleteCharacter removes character and persists", () => {
		const { result } = renderHook(() => usePlayerCharacters(), { wrapper });

		act(() => {
			result.current.createCharacter(
				"Vex",
				15,
				28,
				undefined,
				undefined,
				undefined,
			);
		});

		const id = result.current.characters[0].id;

		act(() => {
			result.current.deleteCharacter(id);
		});

		expect(result.current.characters).toHaveLength(0);
	});
});
