import { useCallback, useEffect, useRef, useState } from "react";
import { Badge, DataList } from "@platform-modules/ui-primitives";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
//#region src/errors.ts
var NotificationClientError = class extends Error {
	code;
	constructor(message, code = "NOTIFICATION_CLIENT_ERROR") {
		super(message);
		this.name = "NotificationClientError";
		this.code = code;
	}
};
function isNotificationClientError(e) {
	return typeof e === "object" && e !== null && e.name === "NotificationClientError";
}
//#endregion
//#region src/useNotifications.ts
function toError(e) {
	return e instanceof Error ? e : new Error(String(e));
}
function useNotifications(client, opts) {
	const [items, setItems] = useState([]);
	const [unread, setUnread] = useState(0);
	const [loading, setLoading] = useState(true);
	const [error, setError] = useState(null);
	const [hasMore, setHasMore] = useState(false);
	const [reloadToken, setReloadToken] = useState(0);
	const clientRef = useRef(client);
	clientRef.current = client;
	const nextCursorRef = useRef(void 0);
	const reload = useCallback(() => {
		setReloadToken((t) => t + 1);
	}, []);
	useEffect(() => {
		let cancelled = false;
		setLoading(true);
		setError(null);
		nextCursorRef.current = void 0;
		Promise.all([clientRef.current.list(), clientRef.current.unreadCount()]).then(([page, count]) => {
			if (!cancelled) {
				setItems(page.items);
				nextCursorRef.current = page.nextCursor;
				setHasMore(Boolean(page.nextCursor));
				setUnread(count);
				setLoading(false);
			}
		}).catch((e) => {
			if (!cancelled) {
				setError(toError(e));
				setLoading(false);
			}
		});
		return () => {
			cancelled = true;
		};
	}, [reloadToken]);
	const loadMore = useCallback(async () => {
		const cursor = nextCursorRef.current;
		if (!cursor) return;
		try {
			const page = await clientRef.current.list({ cursor });
			nextCursorRef.current = page.nextCursor;
			setHasMore(Boolean(page.nextCursor));
			setItems((prev) => [...prev, ...page.items]);
		} catch (e) {
			setError(toError(e));
		}
	}, []);
	const markRead = useCallback(async (ids) => {
		const snapshot = {
			items,
			unread
		};
		if (ids === "all") {
			const now = (/* @__PURE__ */ new Date()).toISOString();
			setItems((prev) => prev.map((item) => ({
				...item,
				readAt: item.readAt ?? now
			})));
			setUnread(0);
		} else {
			const now = (/* @__PURE__ */ new Date()).toISOString();
			let newlyRead = 0;
			setItems((prev) => prev.map((item) => {
				if (ids.includes(item.id) && !item.readAt) {
					newlyRead++;
					return {
						...item,
						readAt: now
					};
				}
				return item;
			}));
			setUnread((u) => Math.max(0, u - newlyRead));
		}
		try {
			await clientRef.current.markRead(ids);
		} catch (e) {
			setItems(snapshot.items);
			setUnread(snapshot.unread);
			const err = toError(e);
			setError(err);
			throw err;
		}
	}, [items, unread]);
	useEffect(() => {
		const pollMs = opts?.pollMs;
		if (!pollMs) return;
		let cancelled = false;
		const id = setInterval(() => {
			clientRef.current.unreadCount().then((count) => {
				if (!cancelled) setUnread(count);
			}).catch((e) => {
				if (!cancelled) setError(toError(e));
			});
		}, pollMs);
		return () => {
			cancelled = true;
			clearInterval(id);
		};
	}, [opts?.pollMs]);
	return {
		items,
		unread,
		loading,
		error,
		hasMore,
		loadMore,
		markRead,
		reload
	};
}
//#endregion
//#region src/NotificationBell.tsx
function NotificationBell({ client, onOpen }) {
	const { unread } = useNotifications(client);
	return /* @__PURE__ */ jsxs("button", {
		type: "button",
		"aria-label": `${unread} unread notifications`,
		onClick: onOpen,
		children: ["Notifications", unread > 0 ? /* @__PURE__ */ jsx(Badge, { children: unread }) : null]
	});
}
//#endregion
//#region src/NotificationList.tsx
function NotificationList({ client, emptyState }) {
	const { items, loading, markRead, hasMore, loadMore } = useNotifications(client);
	if (items.length === 0 && !loading) return /* @__PURE__ */ jsx(Fragment, { children: emptyState ?? null });
	return /* @__PURE__ */ jsxs("div", {
		"aria-live": "polite",
		children: [/* @__PURE__ */ jsx(DataList, { items: items.map((item) => ({
			term: item.title,
			value: /* @__PURE__ */ jsxs(Fragment, { children: [item.body ? /* @__PURE__ */ jsx("span", { children: item.body }) : null, /* @__PURE__ */ jsx("button", {
				type: "button",
				"aria-label": `Mark "${item.title}" read`,
				onClick: () => void markRead([item.id]),
				children: "Mark read"
			})] })
		})) }), hasMore ? /* @__PURE__ */ jsx("button", {
			type: "button",
			onClick: () => void loadMore(),
			children: "Load more"
		}) : null]
	});
}
//#endregion
export { NotificationBell, NotificationClientError, NotificationList, isNotificationClientError, useNotifications };
