import * as Vue from 'vue';
import { isServer } from '@tanstack/router-core/isServer';
import { useStore } from '@tanstack/vue-store';
import { CatchBoundary } from './CatchBoundary';
import { useRouter } from './useRouter';
import { useTransitionerSetup } from './Transitioner';
import { matchContext } from './matchContext';
import { Match } from './Match';
// Create a component that renders MatchesInner with Transitioner's setup logic inlined.
// This is critical for proper hydration - we call useTransitionerSetup() as a composable
// rather than rendering it as a component, which avoids Fragment/element mismatches.
const MatchesContent = Vue.defineComponent({
    name: 'MatchesContent',
    setup() {
        // IMPORTANT: We need to ensure Transitioner's setup() runs.
        // Transitioner sets up critical functionality:
        // - router.startTransition
        // - History subscription via router.history.subscribe(router.load)
        // - Watchers for router events
        //
        // We inline Transitioner's setup logic here. Since Transitioner returns null,
        // we can call its setup function directly without affecting the render tree.
        // This is done by importing and calling useTransitionerSetup.
        useTransitionerSetup();
        return () => Vue.h(MatchesInner);
    },
});
export const Matches = Vue.defineComponent({
    name: 'Matches',
    setup() {
        const router = useRouter();
        return () => {
            const pendingElement = router?.options?.defaultPendingComponent
                ? Vue.h(router.options.defaultPendingComponent)
                : null;
            // Do not render a root Suspense during SSR or hydrating from SSR
            const inner = (isServer ?? router?.isServer ?? false) ||
                (typeof document !== 'undefined' && router?.ssr)
                ? Vue.h(MatchesContent)
                : Vue.h(Vue.Suspense, { fallback: pendingElement }, {
                    default: () => Vue.h(MatchesContent),
                });
            return router?.options?.InnerWrap
                ? Vue.h(router.options.InnerWrap, null, { default: () => inner })
                : inner;
        };
    },
});
// Create a simple error component function that matches ErrorRouteComponent
const errorComponentFn = (props) => {
    return Vue.h('div', { class: 'error' }, [
        Vue.h('h1', null, 'Error'),
        Vue.h('p', null, props.error.message || String(props.error)),
        Vue.h('button', { onClick: props.reset }, 'Try Again'),
    ]);
};
const MatchesInner = Vue.defineComponent({
    name: 'MatchesInner',
    setup() {
        const router = useRouter();
        const matchId = useStore(router.stores.firstId, (id) => id);
        const resetKey = useStore(router.stores.loadedAt, (loadedAt) => loadedAt);
        // Create a ref for the match id to provide
        const matchIdRef = Vue.computed(() => matchId.value);
        // Provide the matchId for child components using the InjectionKey
        Vue.provide(matchContext, matchIdRef);
        return () => {
            // Generate a placeholder element if matchId.value is not present
            const childElement = matchId.value
                ? Vue.h(Match, { matchId: matchId.value })
                : Vue.h('div');
            // If disableGlobalCatchBoundary is true, don't wrap in CatchBoundary
            if (router.options.disableGlobalCatchBoundary) {
                return childElement;
            }
            return Vue.h(CatchBoundary, {
                getResetKey: () => resetKey.value,
                errorComponent: errorComponentFn,
                onCatch: process.env.NODE_ENV !== 'production'
                    ? (error) => {
                        console.warn(`Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`);
                        console.warn(`Warning: ${error.message || error.toString()}`);
                    }
                    : undefined,
                children: childElement,
            });
        };
    },
});
export function useMatchRoute() {
    const router = useRouter();
    const routerState = useStore(router.stores.matchRouteDeps, (value) => value);
    return (opts) => {
        const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts;
        const matchRoute = Vue.computed(() => {
            // Access routerState to establish dependency
            routerState.value;
            return router.matchRoute(rest, {
                pending,
                caseSensitive,
                fuzzy,
                includeSearch,
            });
        });
        return matchRoute;
    };
}
export const MatchRoute = Vue.defineComponent({
    name: 'MatchRoute',
    props: {
        // Define props to match MakeMatchRouteOptions
        from: {
            type: String,
            required: false,
        },
        to: {
            type: String,
            required: false,
        },
        fuzzy: {
            type: Boolean,
            required: false,
        },
        caseSensitive: {
            type: Boolean,
            required: false,
        },
        includeSearch: {
            type: Boolean,
            required: false,
        },
        pending: {
            type: Boolean,
            required: false,
        },
    },
    setup(props, { slots }) {
        const router = useRouter();
        const status = useStore(router.stores.matchRouteDeps, (value) => value.status);
        return () => {
            if (!status.value)
                return null;
            const matchRoute = useMatchRoute();
            const params = matchRoute(props).value;
            // Create a component that renders the slot in a reactive manner
            if (!params || !slots.default) {
                return null;
            }
            // For function slots, pass the params
            if (typeof slots.default === 'function') {
                // Use h to create a wrapper component that will call the slot function
                return Vue.h(Vue.Fragment, null, slots.default(params));
            }
            // For normal slots, just render them
            return Vue.h(Vue.Fragment, null, slots.default);
        };
    },
});
export function useMatches(opts) {
    const router = useRouter();
    return useStore(router.stores.matches, (matches) => {
        return opts?.select
            ? opts.select(matches)
            : matches;
    });
}
export function useParentMatches(opts) {
    // Use matchContext with proper type
    const contextMatchId = Vue.inject(matchContext);
    const safeMatchId = Vue.computed(() => contextMatchId?.value || '');
    return useMatches({
        select: (matches) => {
            matches = matches.slice(0, matches.findIndex((d) => d.id === safeMatchId.value));
            return opts?.select ? opts.select(matches) : matches;
        },
    });
}
export function useChildMatches(opts) {
    // Use matchContext with proper type
    const contextMatchId = Vue.inject(matchContext);
    const safeMatchId = Vue.computed(() => contextMatchId?.value || '');
    return useMatches({
        select: (matches) => {
            matches = matches.slice(matches.findIndex((d) => d.id === safeMatchId.value) + 1);
            return opts?.select ? opts.select(matches) : matches;
        },
    });
}
//# sourceMappingURL=Matches.jsx.map