import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page, userEvent } from 'vitest/browser';
import TestHost from './confirm.test-fixture.svelte';
import type { ConfirmService } from './confirm.svelte.js';

afterEach(cleanup);

function makeHost(): { service: ConfirmService } {
	const result: { service: ConfirmService | null } = { service: null };
	render(TestHost, {
		onReady: (s: ConfirmService) => {
			result.service = s;
		}
	});
	return result as { service: ConfirmService };
}

describe('ConfirmService', () => {
	it('resolves true when the user clicks Confirm', async () => {
		const { service } = makeHost();

		const resultPromise = service.confirm({ title: 'Test?' });
		await expect.element(page.getByRole('dialog')).toBeInTheDocument();
		await page.getByRole('button', { name: 'Bestätigen' }).click();

		expect(await resultPromise).toBe(true);
	});

	it('resolves false when the user clicks Cancel', async () => {
		const { service } = makeHost();

		const resultPromise = service.confirm({ title: 'Test?' });
		await expect.element(page.getByRole('dialog')).toBeInTheDocument();
		await page.getByRole('button', { name: 'Abbrechen' }).click();

		expect(await resultPromise).toBe(false);
	});

	it('resolves false when Escape is pressed', async () => {
		const { service } = makeHost();

		const resultPromise = service.confirm({ title: 'Test?' });
		await expect.element(page.getByRole('dialog')).toBeInTheDocument();
		await userEvent.keyboard('{Escape}');

		expect(await resultPromise).toBe(false);
	});

	it('resolves false immediately on a concurrent call while dialog is open', async () => {
		const { service } = makeHost();

		const first = service.confirm({ title: 'First?' });
		await expect.element(page.getByRole('dialog')).toBeInTheDocument();

		const second = service.confirm({ title: 'Second?' });
		expect(await second).toBe(false);

		// clean up the first dialog
		await page.getByRole('button', { name: 'Abbrechen' }).click();
		expect(await first).toBe(false);
	});

	it('throws a descriptive error when called outside provider tree', async () => {
		const { getConfirmService } = await import('./confirm.svelte.js');
		// Outside component init, getContext throws or returns undefined — our guard
		// converts either case to a descriptive developer error
		expect(() => getConfirmService()).toThrow('mount <ConfirmDialog>');
	});
});
