import {createContext, useCallback, useContext, useEffect, useMemo, useRef} from 'react';

interface ContainerListenerContextI {
    eventFired: () => void;
    registerListener: (fn: () => void) => void;
    deregisterListener: (fn: () => void) => void;
}

const BodyListenerContext = createContext<ContainerListenerContextI | null>(null);
const useBodyListenerContext = () => useContext(BodyListenerContext);
export const BodyListenerProvider = BodyListenerContext.Provider;

export function useRegisterListener(fn: () => void) {
    const context = useBodyListenerContext();

    return useEffect(() => {
        if (context) context.registerListener(fn);
        return () => {
            if (context) context.deregisterListener(fn);
        };
    }, [fn]);
}

export function useListener(): ContainerListenerContextI {
    const listeners = useRef<(() => void)[]>([]);

    const registerListener = useCallback((fn: () => void) => {
        listeners.current.push(fn);
    }, []);

    const deregisterListener = useCallback((fn: () => void) => {
        listeners.current = listeners.current.filter((v) => v !== fn);
    }, []);

    const eventFired = useCallback(() => {
        listeners.current.map((fn) => fn());
    }, []);

    return useMemo(
        () => ({
            eventFired,
            registerListener,
            deregisterListener
        }),
        []
    );
}
