import { jsx as _jsx, Fragment as _Fragment } from "@emotion/react/jsx-runtime";
import { cloneElement, Fragment, isValidElement, useMemo, useEffect, useRef, createElement, useLayoutEffect, } from 'react';
import { RouteType } from '.';
import { makeMatcher } from './matcher';
import { useRouter, useLocation, buildRouter, RouterCtx, useNavigate, } from './hooks';
export const Route = ({ match, children, mergeState }) => {
    const [matches, params] = match || [false, null];
    useEffect(() => {
        matches && mergeState(params);
        return () => {
            if (!matches) {
                return;
            }
            const destroyObj = {};
            for (const key in params) {
                destroyObj[key] = undefined;
            }
            mergeState(destroyObj);
        };
    }, [params]);
    if (!matches)
        return null;
    return typeof children === 'function' ? children(params) : children;
};
export const Switch = ({ switchPolicy, location, slotMap, mergeState, subscribeMethods, }) => {
    const [originalLocation] = useLocation();
    const matcher = useMemo(() => makeMatcher(), []);
    const [loc, naviagte] = useLocation();
    const routes = useMemo(() => {
        let defaultPath = undefined;
        const result = switchPolicy.map(({ type, path, slotId, href, default: _default, exact, strict, sensitive }) => {
            const componentsArr = slotMap && slotMap.get(slotId);
            if (defaultPath === undefined && _default) {
                defaultPath = path;
            }
            switch (type.toUpperCase()) {
                case RouteType.REDIRECT:
                    return (_jsx(Route, Object.assign({ exact: exact, strict: strict, sensitive: sensitive, path: path, mergeState: mergeState }, { children: _jsx(Redirect, { href: href || path }, void 0) }), path));
                case RouteType.ROUTE:
                    if (!componentsArr) {
                        console.warn('component not registered to router');
                        return _jsx(_Fragment, {}, void 0);
                    }
                    if (componentsArr.length !== 1) {
                        console.warn('router slot can only have one component');
                    }
                    const { component: C } = componentsArr[0];
                    if (C.displayName === 'router') {
                        return (_jsx(Nested, Object.assign({ path: `(${path}|${path}/.*)`, base: path }, { children: _jsx(C, {}, slotId) }), path));
                    }
                    return (_jsx(Route, Object.assign({ exact: exact, strict: strict, sensitive: sensitive, path: path, mergeState: mergeState }, { children: _jsx(C, {}, slotId) }), path));
                default:
                    console.warn('unsupport router type');
                    return _jsx(_Fragment, {}, void 0);
            }
        });
        if (defaultPath) {
            result.push(_jsx(Route, Object.assign({ mergeState: mergeState }, { children: _jsx(Redirect, { href: defaultPath }, void 0) }), void 0));
        }
        return result;
    }, [switchPolicy]);
    useEffect(() => {
        subscribeMethods({
            navigate: (path) => {
                naviagte(path);
            },
        });
    }, []);
    useEffect(() => {
        mergeState({
            route: loc,
        });
        () => {
            mergeState({
                route: undefined,
            });
        };
    }, [loc]);
    for (const element of flattenChildren(routes)) {
        const match = element.props.path
            ? matcher(location || originalLocation, element.props)
            : [true, {}];
        if (isValidElement(element) && match[0])
            return cloneElement(element, { match });
    }
    return null;
};
export const Nested = ({ children, base }) => {
    const router = useRouter();
    const [parentLocation] = useLocation();
    const nestedBase = `${router.base}${base}`;
    if (!parentLocation.startsWith(base)) {
        return null;
    }
    return (_jsx(Wouter, Object.assign({ base: nestedBase }, { children: children }), nestedBase));
};
export const Wouter = (props) => {
    const ref = useRef();
    const value = ref.current || (ref.current = { v: buildRouter(props) });
    return createElement(RouterCtx.Provider, {
        value,
    }, props.children);
};
export const Redirect = props => {
    const navRef = useNavigate(props);
    useLayoutEffect(() => {
        navRef.current();
    }, []);
    return null;
};
const flattenChildren = (children) => {
    if (!children) {
        return [];
    }
    return Array.isArray(children)
        ? [].concat(...children.map(c => c.type === Fragment
            ? flattenChildren(c.props.children)
            : flattenChildren(c)))
        : [children];
};
//# sourceMappingURL=component.js.map