import React__default, { useCallback, useMemo, useEffect } from 'react';
import { noop } from './shared/utils/noop.mjs';
import { useBeforeUnloadNavigationBlock } from './utils/useNavigateAwayWarning.mjs';

const routerReducer = (state, action)=>{
    switch(action.type){
        case 'navigate':
            if (state.blockersActive.size > 0) {
                return {
                    ...state,
                    pendingRoute: action.payload
                };
            }
            return {
                ...state,
                currentRoute: action.payload,
                pendingRoute: undefined
            };
        case 'addBlocker':
            {
                const blockersActive = new Set(state.blockersActive);
                blockersActive.add(action.payload.callback);
                return {
                    ...state,
                    blockersActive
                };
            }
        case 'removeBlocker':
            {
                const blockersActive = new Set(state.blockersActive);
                blockersActive.delete(action.payload.callback);
                if (blockersActive.size === 0 && state.pendingRoute) {
                    return {
                        ...state,
                        blockersActive,
                        currentRoute: state.pendingRoute,
                        pendingRoute: undefined
                    };
                }
                return {
                    ...state,
                    blockersActive
                };
            }
        case 'approveNavigation':
            if (!state.pendingRoute) {
                return state;
            }
            return {
                ...state,
                currentRoute: state.pendingRoute,
                pendingRoute: undefined
            };
        case 'cancelNavigation':
            return {
                ...state,
                pendingRoute: undefined
            };
        default:
            return state;
    }
};
const createRouter = ()=>{
    const initialState = {
        blockersActive: new Set()
    };
    // TODO: consider throwing if not initialized
    const StateContext = /*#__PURE__*/ React__default.createContext({});
    // TODO: consider throwing if not initialized
    const ControllerContext = /*#__PURE__*/ React__default.createContext({
        navigate: noop,
        useBlockNavigation: ()=>({
                blocked: false,
                allowNavigation: noop,
                cancelNavigation: noop
            })
    });
    const useRouterState = ()=>{
        return React__default.useContext(StateContext);
    };
    const useRouterController = ()=>{
        return React__default.useContext(ControllerContext);
    };
    const Router = ({ routeMap })=>{
        const { currentRoute } = useRouterState();
        const ChildComponent = routeMap[currentRoute.screen];
        const childComponentProps = currentRoute.params;
        return ChildComponent ? /*#__PURE__*/ React__default.createElement(ChildComponent, childComponentProps) : null;
    };
    const RouterProvider = ({ children, initialRoute })=>{
        const [state, dispatch] = React__default.useReducer(routerReducer, {
            ...initialState,
            currentRoute: initialRoute
        });
        const navigate = useCallback((destination)=>{
            dispatch({
                type: 'navigate',
                payload: destination
            });
        }, []);
        const routerState = useMemo(()=>({
                currentRoute: state.currentRoute
            }), [
            state.currentRoute
        ]);
        const isNavigationBlocked = !!state.pendingRoute;
        const useBlockNavigation = useCallback((enableBlock)=>{
            // eslint-disable-next-line react-hooks/rules-of-hooks -- hook definition inside callback
            const callback = useMemo(()=>typeof enableBlock === 'function' ? enableBlock : ()=>enableBlock, [
                enableBlock
            ]);
            // eslint-disable-next-line react-hooks/rules-of-hooks -- hook definition inside callback
            useEffect(()=>{
                const shouldEnableBlock = callback();
                if (shouldEnableBlock) {
                    dispatch({
                        type: 'addBlocker',
                        payload: {
                            callback
                        }
                    });
                    return ()=>{
                        dispatch({
                            type: 'removeBlocker',
                            payload: {
                                callback
                            }
                        });
                    };
                }
            }, [
                callback,
                enableBlock
            ]);
            return {
                blocked: isNavigationBlocked,
                allowNavigation: ()=>{
                    dispatch({
                        type: 'approveNavigation'
                    });
                },
                cancelNavigation: ()=>{
                    dispatch({
                        type: 'cancelNavigation'
                    });
                }
            };
        }, [
            isNavigationBlocked
        ]);
        useBeforeUnloadNavigationBlock(state.blockersActive.size > 0);
        const controller = useMemo(()=>{
            return {
                navigate,
                useBlockNavigation
            };
        }, [
            navigate,
            useBlockNavigation
        ]);
        return /*#__PURE__*/ React__default.createElement(ControllerContext.Provider, {
            value: controller
        }, /*#__PURE__*/ React__default.createElement(StateContext.Provider, {
            value: routerState
        }, children));
    };
    return {
        RouterProvider,
        Router,
        useRouterController,
        useRouterState
    };
};

export { createRouter };
//# sourceMappingURL=Router.mjs.map
