import Cookies from 'js-cookie';
import { useCallback, useEffect, useState } from 'react';
import { useFirstMountState } from '../useFirstMountState/index.js';
import { useMountEffect } from '../useMountEffect/index.js';
import { useSyncedRef } from '../useSyncedRef/index.js';
import { isBrowser } from '../util/const.js';
const cookiesSetters = new Map();
const registerSetter = (key, setter) => {
    let setters = cookiesSetters.get(key);
    if (!setters) {
        setters = new Set();
        cookiesSetters.set(key, setters);
    }
    setters.add(setter);
};
const unregisterSetter = (key, setter) => {
    const setters = cookiesSetters.get(key);
    if (!setters)
        return;
    setters.delete(setter);
    if (setters.size === 0) {
        cookiesSetters.delete(key);
    }
};
const invokeRegisteredSetters = (key, value, skipSetter) => {
    const setters = cookiesSetters.get(key);
    if (!setters)
        return;
    for (const s of setters) {
        if (s !== skipSetter)
            s(value);
    }
};
export function useCookieValue(key, options = {}) {
    if (process.env.NODE_ENV === 'development' && Cookies === undefined) {
        throw new ReferenceError('Dependency `js-cookies` is not installed, it is required for `useCookieValue` work.');
    }
    let { initializeWithValue = true, ...cookiesOptions } = options;
    if (!isBrowser) {
        initializeWithValue = false;
    }
    const methods = useSyncedRef({
        set(value) {
            setState(value);
            Cookies.set(key, value, cookiesOptions);
            invokeRegisteredSetters(key, value, setState);
        },
        remove() {
            setState(null);
            Cookies.remove(key, cookiesOptions);
            invokeRegisteredSetters(key, null, setState);
        },
        fetchVal: () => Cookies.get(key) ?? null,
        fetch() {
            const value = methods.current.fetchVal();
            setState(value);
            invokeRegisteredSetters(key, value, setState);
        },
    });
    const isFirstMount = useFirstMountState();
    const [state, setState] = useState(isFirstMount && initializeWithValue ? methods.current.fetchVal() : undefined);
    useMountEffect(() => {
        if (!initializeWithValue) {
            methods.current.fetch();
        }
    });
    useEffect(() => {
        registerSetter(key, setState);
        return () => {
            unregisterSetter(key, setState);
        };
    }, [key]);
    return [
        state,
        useCallback((value) => {
            methods.current.set(value);
        }, []),
        useCallback(() => {
            methods.current.remove();
        }, []),
        useCallback(() => {
            methods.current.fetch();
        }, []),
    ];
}
