import { afterEach, describe, it, expect, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import type { NotificationItem } from '$lib/notification/notifications';
import NotificationBell from './NotificationBell.svelte';

const gotoMock = vi.hoisted(() => vi.fn());
vi.mock('$app/navigation', () => ({ goto: gotoMock, beforeNavigate: vi.fn() }));

const mockMarkRead = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
const mockNotificationList = vi.hoisted((): { value: NotificationItem[] } => ({ value: [] }));

vi.mock('$lib/notification/notifications.svelte', () => ({
	notificationStore: {
		get notifications() {
			return mockNotificationList.value;
		},
		get unreadCount() {
			return mockNotificationList.value.length;
		},
		markRead: mockMarkRead,
		fetchNotifications: vi.fn().mockResolvedValue(undefined),
		init: vi.fn(),
		destroy: vi.fn(),
		markAllRead: vi.fn()
	}
}));

afterEach(() => {
	cleanup();
	gotoMock.mockClear();
	mockMarkRead.mockClear();
	mockNotificationList.value = [];
});

const makeNotification = (overrides: Partial<NotificationItem> = {}): NotificationItem => ({
	id: 'n1',
	type: 'REPLY',
	documentId: 'doc-1',
	referenceId: 'ref-1',
	annotationId: null,
	read: false,
	createdAt: '2026-04-21T10:00:00Z',
	actorName: 'Anna',
	documentTitle: 'Test Doc',
	...overrides
});

async function openDropdownAndClickFirstNotification() {
	const bellButton = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
	bellButton.click();
	await vi.waitFor(() => {
		expect(document.querySelector('[role="dialog"]')).not.toBeNull();
	});
	const notifButton = document.querySelector<HTMLButtonElement>('[role="list"] button')!;
	notifButton.click();
}

describe('NotificationBell — cursor and tooltip', () => {
	it('bell button has cursor-pointer class', async () => {
		render(NotificationBell);
		const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
		expect(btn.classList.contains('cursor-pointer')).toBe(true);
	});

	it('bell button title equals aria-label when unreadCount is 0', async () => {
		mockNotificationList.value = [];
		render(NotificationBell);
		const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
		expect(btn.getAttribute('title')).toBe('Benachrichtigungen');
		expect(btn.getAttribute('aria-label')).toBe(btn.getAttribute('title'));
	});

	it('bell button title equals aria-label when unreadCount is 3', async () => {
		mockNotificationList.value = [
			makeNotification({ id: 'n1' }),
			makeNotification({ id: 'n2' }),
			makeNotification({ id: 'n3' })
		];
		render(NotificationBell);
		const btn = document.querySelector<HTMLButtonElement>('button[aria-haspopup="true"]')!;
		expect(btn.getAttribute('title')).toBe('3 ungelesene Benachrichtigungen');
		expect(btn.getAttribute('aria-label')).toBe(btn.getAttribute('title'));
	});
});

describe('NotificationBell', () => {
	it('handleMarkRead navigates to URL including annotationId when notification has annotationId', async () => {
		mockNotificationList.value = [makeNotification({ annotationId: 'annot-1' })];
		render(NotificationBell);

		await openDropdownAndClickFirstNotification();

		await vi.waitFor(() => {
			expect(gotoMock).toHaveBeenCalledWith(
				'/documents/doc-1?commentId=ref-1&annotationId=annot-1'
			);
		});
	});

	it('handleMarkRead navigates to commentId-only URL when annotationId is absent', async () => {
		mockNotificationList.value = [makeNotification({ annotationId: null })];
		render(NotificationBell);

		await openDropdownAndClickFirstNotification();

		await vi.waitFor(() => {
			expect(gotoMock).toHaveBeenCalledWith('/documents/doc-1?commentId=ref-1');
		});
	});
});
