import React, { createContext, useMemo, useCallback, useContext } from "react";
import differenceBy from "lodash/differenceBy";
import { fromPromise } from "xstate";
import { useMachine } from "@xstate/react";
import { localizeAnnouncements, filterAnnouncements } from "./logic";
import defaultFetchApi from "./api";
import { announcementMachine } from "./machine";
const AnnouncementsContext = createContext({
    seenIds: [],
    allIds: [],
    cache: {},
    isLoading: false,
    lastUpdateTime: undefined,
    error: undefined,
    updateCache: () => Promise.resolve(),
    setAsSeen: () => { },
});
export function useAnnouncements() {
    return useContext(AnnouncementsContext);
}
export const AnnouncementProvider = ({ children, context, handleLoad, handleSave, autoUpdateDelay, onNewAnnouncement, onAnnouncementRead, fetchApi = defaultFetchApi, }) => {
    const fetchData = useCallback(async (arg0) => {
        const { allIds, cache } = arg0.input;
        const rawAnnouncements = await fetchApi.fetchAnnouncements();
        const localizedAnnouncements = localizeAnnouncements(rawAnnouncements, context);
        const announcements = filterAnnouncements(localizedAnnouncements, context);
        const oldAnnouncements = allIds.map((uuid) => cache[uuid]);
        const newAnnouncements = differenceBy(announcements, oldAnnouncements, announcement => announcement.uuid);
        if (onNewAnnouncement) {
            newAnnouncements.forEach(announcement => {
                onNewAnnouncement(announcement);
            });
        }
        return {
            announcements,
            updateTime: Date.now(),
        };
    }, [context, onNewAnnouncement, fetchApi]);
    const emitNewAnnouncement = useCallback(({ context }) => {
        if (onAnnouncementRead) {
            onAnnouncementRead(context.cache[context.seenId]);
        }
    }, [onAnnouncementRead]);
    const loadData = useCallback(async () => {
        const { announcements, lastUpdateTime, seenIds } = await handleLoad();
        return {
            announcements,
            lastUpdateTime,
            seenIds,
        };
    }, [handleLoad]);
    const saveData = useCallback(({ context }) => {
        const { cache, lastUpdateTime, seenIds, allIds } = context;
        const announcements = allIds.map((id) => cache[id]);
        handleSave({
            announcements,
            seenIds,
            lastUpdateTime,
        });
    }, [handleSave]);
    const [state, send] = useMachine(announcementMachine.provide({
        actions: {
            saveData,
            emitNewAnnouncement,
        },
        actors: {
            loadData: fromPromise(loadData),
            fetchData: fromPromise(fetchData),
        },
        delays: {
            AUTO_UPDATE_DELAY: autoUpdateDelay,
        },
    }));
    const api = useMemo(() => ({
        updateCache: async () => {
            send({
                type: "UPDATE_DATA",
            });
        },
        setAsSeen: (seenId) => {
            send({
                type: "SET_AS_SEEN",
                seenId,
            });
        },
    }), [send]);
    const value = { ...state.context, ...api };
    return (React.createElement(AnnouncementsContext.Provider, { value: value }, children));
};
//# sourceMappingURL=index.js.map