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

const mockFormResult = vi.hoisted(() => ({ type: 'success' as string }));

vi.mock('$app/forms', () => ({
	enhance(
		node: HTMLFormElement,
		submit?: (opts: {
			formData: FormData;
		}) => (opts: {
			result: { type: string; data?: Record<string, unknown> };
			update: () => Promise<void>;
		}) => Promise<void>
	) {
		const handler = async (e: Event) => {
			e.preventDefault();
			const cb = submit?.({ formData: new FormData(node) } as never);
			if (typeof cb === 'function') {
				await (
					cb as (o: { result: typeof mockFormResult; update: () => Promise<void> }) => Promise<void>
				)({ result: mockFormResult, update: async () => {} });
			}
		};
		node.addEventListener('submit', handler);
		return { destroy: () => node.removeEventListener('submit', handler) };
	}
}));

afterEach(() => {
	cleanup();
	mockFormResult.type = 'success';
});

const mention = (overrides: Partial<NotificationItem> = {}): NotificationItem => ({
	id: 'n-1',
	type: 'MENTION',
	documentId: 'doc-1',
	referenceId: 'ref-1',
	annotationId: null,
	read: false,
	createdAt: new Date().toISOString(),
	actorName: 'Anna',
	documentTitle: 'Brief 1899',
	...overrides
});

describe('ChronikFuerDichBox', () => {
	it('renders the inbox-zero state when there are no unread', async () => {
		render(ChronikFuerDichBox, {
			props: { unread: [], optimisticMarkRead: () => {}, optimisticMarkAllRead: () => {} }
		});

		await expect.element(page.getByText(/keine neuen erwähnungen/i)).toBeVisible();
		const link = document.querySelector('a[href="/aktivitaeten?filter=fuer-dich"]');
		expect(link).not.toBeNull();
	});

	it('renders the count badge with the unread count', async () => {
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention(), mention({ id: 'n-2' }), mention({ id: 'n-3' })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		const badge = document.querySelector('[data-testid="chronik-fuerdich-count"]');
		expect(badge?.textContent).toContain('3');
	});

	it('uses the @ glyph for MENTION and ↩ for REPLY', async () => {
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention({ id: 'n-m', type: 'MENTION' }), mention({ id: 'n-r', type: 'REPLY' })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		const items = document.querySelectorAll('ul[role="list"] li');
		expect(items.length).toBe(2);
		expect(items[0].textContent).toContain('@');
		expect(items[1].textContent).toContain('↩');
	});

	it('renders MENTION verb text from paraglide messages', async () => {
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention({ actorName: 'Bertha' })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		await expect
			.element(page.getByText(/bertha hat dich in einem kommentar erwähnt/i))
			.toBeVisible();
	});

	it('renders REPLY verb text from paraglide messages', async () => {
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention({ type: 'REPLY', actorName: 'Carl' })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		await expect
			.element(page.getByText(/carl hat auf deinen kommentar geantwortet/i))
			.toBeVisible();
	});

	it('calls optimisticMarkRead with the notification id when its dismiss button is clicked', async () => {
		const optimisticMarkRead = vi.fn();
		const item = mention({ id: 'n-7' });
		render(ChronikFuerDichBox, {
			props: { unread: [item], optimisticMarkRead, optimisticMarkAllRead: () => {} }
		});

		const dismiss = document.querySelector(
			'[data-testid="chronik-fuerdich-dismiss"]'
		) as HTMLElement;
		dismiss.click();

		expect(optimisticMarkRead).toHaveBeenCalledWith('n-7');
	});

	it('calls optimisticMarkAllRead when the mark-all-read button is clicked', async () => {
		const optimisticMarkAllRead = vi.fn();
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention()],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead
			}
		});

		const btn = document.querySelector('[data-testid="chronik-mark-all-read"]') as HTMLElement;
		btn.click();

		expect(optimisticMarkAllRead).toHaveBeenCalledOnce();
	});

	it('builds a deep-link href to the comment for each notification', async () => {
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention({ documentId: 'doc-x', referenceId: 'ref-y', annotationId: null })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		const link = document.querySelector('ul[role="list"] li a') as HTMLAnchorElement;
		expect(link.getAttribute('href')).toContain('doc-x');
	});

	it('shows an accessible error banner when the dismiss action returns a failure', async () => {
		mockFormResult.type = 'failure';
		render(ChronikFuerDichBox, {
			props: {
				unread: [mention({ id: 'err-1' })],
				optimisticMarkRead: () => {},
				optimisticMarkAllRead: () => {}
			}
		});

		const dismiss = document.querySelector(
			'[data-testid="chronik-fuerdich-dismiss"]'
		) as HTMLElement;
		dismiss.click();
		// Allow microtask queue to flush
		await new Promise((r) => setTimeout(r, 0));
		const alert = document.querySelector('[role="alert"]');
		expect(alert).not.toBeNull();
	});
});
