import { type NotificationItem, parseNotificationEvent } from '$lib/notification/notifications';

export type { NotificationItem };

let notifications = $state<NotificationItem[]>([]);
let unreadCount = $state(0);
let eventSource: EventSource | null = null;
let refCount = 0;
let errorCount = 0;
let navigate: (url: string) => void = (url) => {
	window.location.href = url;
};

async function fetchNotifications(): Promise<void> {
	try {
		const res = await fetch('/api/notifications?size=10');
		if (res.ok) {
			const data = await res.json();
			notifications = data.content ?? [];
		}
	} catch (e) {
		console.error('Failed to fetch notifications', e);
	}
}

async function fetchUnreadCount(): Promise<void> {
	try {
		const res = await fetch('/api/notifications/unread-count');
		if (res.ok) {
			const data = await res.json();
			unreadCount = data.count;
		}
	} catch (e) {
		console.error('Failed to fetch unread count', e);
	}
}

function optimisticMarkRead(id: string): void {
	const notification = notifications.find((n) => n.id === id);
	if (notification && !notification.read) {
		notification.read = true;
		unreadCount = Math.max(0, unreadCount - 1);
	}
}

function optimisticMarkAllRead(): void {
	for (const n of notifications) {
		n.read = true;
	}
	unreadCount = 0;
}

function init(): void {
	refCount += 1;
	if (refCount > 1) return;

	fetchUnreadCount();
	eventSource = new EventSource('/api/notifications/stream');
	eventSource.addEventListener('notification', (e) => {
		const notification = parseNotificationEvent((e as MessageEvent).data);
		if (!notification) return;
		notifications = [notification, ...notifications];
		if (!notification.read) unreadCount += 1;
	});
	eventSource.onopen = () => {
		fetchUnreadCount();
		errorCount = 0;
	};
	eventSource.onerror = async () => {
		if (eventSource?.readyState === EventSource.CLOSED) {
			const res = await fetch('/api/notifications/unread-count');
			if (res.status === 401) navigate('/login');
			return;
		}
		errorCount += 1;
		if (errorCount >= 3) {
			eventSource?.close();
			eventSource = null;
			errorCount = 0;
			const res = await fetch('/api/notifications/unread-count');
			if (res.status === 401) navigate('/login');
		}
	};
}

function destroy(): void {
	if (refCount === 0) return;
	refCount -= 1;
	if (refCount === 0) {
		eventSource?.close();
		eventSource = null;
	}
}

export function __resetForTest(): void {
	eventSource?.close();
	eventSource = null;
	refCount = 0;
	errorCount = 0;
	notifications = [];
	unreadCount = 0;
}

export function __setNavigateForTest(fn: (url: string) => void): void {
	navigate = fn;
}

export const notificationStore = {
	get notifications() {
		return notifications;
	},
	get unreadCount() {
		return unreadCount;
	},
	fetchNotifications,
	fetchUnreadCount,
	optimisticMarkRead,
	optimisticMarkAllRead,
	init,
	destroy
};
