import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import FileSwitcherStrip from './FileSwitcherStrip.svelte';

afterEach(cleanup);

const makeEntry = (id: string, title: string, overrides: Record<string, unknown> = {}) => ({
	id,
	title,
	status: 'idle' as 'idle' | 'error',
	previewUrl: '',
	...overrides
});

describe('FileSwitcherStrip', () => {
	it('renders the prev and next buttons', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A.pdf')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		await expect.element(page.getByRole('button', { name: /vorherige datei/i })).toBeVisible();
		await expect.element(page.getByRole('button', { name: /nächste datei/i })).toBeVisible();
	});

	it('renders one chip per file', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A.pdf'), makeEntry('f2', 'B.pdf'), makeEntry('f3', 'C.pdf')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const chips = document.querySelectorAll('[data-chip-id]');
		expect(chips.length).toBe(3);
	});

	it('marks the active chip with aria-current=true', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
				activeId: 'f2',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const f2 = document.querySelector('[data-chip-id="f2"]') as HTMLElement;
		const f1 = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
		expect(f2.getAttribute('aria-current')).toBe('true');
		expect(f1.getAttribute('aria-current')).toBeNull();
	});

	it('shows the error indicator on chips with status="error"', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A.pdf', { status: 'error' })],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const chip = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
		expect(chip.getAttribute('data-status')).toBe('error');
	});

	it('calls onSelect with the chip id when clicked', async () => {
		const onSelect = vi.fn();
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
				activeId: 'f1',
				onSelect,
				onRemove: () => {}
			}
		});

		const f2 = document.querySelector('[data-chip-id="f2"]') as HTMLElement;
		f2.click();

		expect(onSelect).toHaveBeenCalledWith('f2');
	});

	it('calls onRemove when the remove button is clicked', async () => {
		const onRemove = vi.fn();
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove
			}
		});

		const remove = document.querySelector('[data-remove-id="f1"]') as HTMLElement;
		remove.click();

		expect(onRemove).toHaveBeenCalledWith('f1');
	});

	it('renders the active title in the sr-only announcer', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'Ein Brief.pdf'), makeEntry('f2', 'B')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const announcer = document.querySelector('[aria-live="polite"]');
		expect(announcer?.textContent).toContain('Ein Brief.pdf');
	});

	it('prev button on a single-file strip is a no-op (active chip stays)', async () => {
		const onSelect = vi.fn();
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A.pdf')],
				activeId: 'f1',
				onSelect,
				onRemove: () => {}
			}
		});

		await page.getByRole('button', { name: /vorherige datei/i }).click();

		// The active chip is still f1 and onSelect was not invoked with a different id.
		expect(document.querySelector('[data-chip-id="f1"]')?.getAttribute('aria-current')).toBe(
			'true'
		);
		expect(onSelect).not.toHaveBeenCalled();
	});

	it('next button on a single-file strip is a no-op (active chip stays)', async () => {
		const onSelect = vi.fn();
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A.pdf')],
				activeId: 'f1',
				onSelect,
				onRemove: () => {}
			}
		});

		await page.getByRole('button', { name: /nächste datei/i }).click();

		expect(document.querySelector('[data-chip-id="f1"]')?.getAttribute('aria-current')).toBe(
			'true'
		);
		expect(onSelect).not.toHaveBeenCalled();
	});

	it('navigates with ArrowRight key on focused chip', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B'), makeEntry('f3', 'C')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const f1 = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
		f1.focus();
		f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));

		await vi.waitFor(() => {
			expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2');
		});
	});

	it('navigates with ArrowLeft key on focused chip (wraps around)', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const f1 = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
		f1.focus();
		f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true }));

		await vi.waitFor(() => {
			// ArrowLeft from index 0 wraps to last (f2).
			expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2');
		});
	});

	it('ArrowDown is treated as ArrowRight (vertical key alias)', async () => {
		render(FileSwitcherStrip, {
			props: {
				files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
				activeId: 'f1',
				onSelect: () => {},
				onRemove: () => {}
			}
		});

		const f1 = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
		f1.focus();
		f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));

		await vi.waitFor(() => {
			expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2');
		});
	});
});
