import { describe, it, expect, afterEach } from 'vitest';

const { trapFocus } = await import('./trapFocus');

describe('trapFocus action', () => {
	const nodes: HTMLElement[] = [];

	function makeContainer(buttonLabels: string[]): {
		node: HTMLElement;
		buttons: HTMLButtonElement[];
	} {
		const node = document.createElement('div');
		const buttons = buttonLabels.map((label) => {
			const b = document.createElement('button');
			b.textContent = label;
			node.appendChild(b);
			return b;
		});
		document.body.appendChild(node);
		nodes.push(node);
		return { node, buttons };
	}

	afterEach(() => {
		nodes.forEach((n) => n.remove());
		nodes.length = 0;
	});

	it('focuses the first focusable element on mount', () => {
		const { node, buttons } = makeContainer(['one', 'two']);
		trapFocus(node);
		expect(document.activeElement).toBe(buttons[0]);
	});

	it('wraps Tab from the last focusable back to the first', () => {
		const { node, buttons } = makeContainer(['one', 'two']);
		trapFocus(node);
		buttons[1].focus();
		node.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }));
		expect(document.activeElement).toBe(buttons[0]);
	});

	it('wraps Shift+Tab from the first focusable to the last', () => {
		const { node, buttons } = makeContainer(['one', 'two']);
		trapFocus(node);
		buttons[0].focus();
		node.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', shiftKey: true, bubbles: true }));
		expect(document.activeElement).toBe(buttons[1]);
	});

	it('removes its listener on destroy', () => {
		const { node, buttons } = makeContainer(['one', 'two']);
		const handle = trapFocus(node);
		handle.destroy();
		buttons[1].focus();
		node.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }));
		// No trap after destroy → focus stays on the last button.
		expect(document.activeElement).toBe(buttons[1]);
	});

	it('restores focus to the previously-focused element on destroy (WCAG 2.4.3)', () => {
		const opener = document.createElement('button');
		document.body.appendChild(opener);
		nodes.push(opener);
		opener.focus();
		expect(document.activeElement).toBe(opener);

		const { node } = makeContainer(['one', 'two']);
		const handle = trapFocus(node);
		expect(document.activeElement).not.toBe(opener);

		handle.destroy();
		expect(document.activeElement).toBe(opener);
	});
});
