import * as Vue from 'vue';
import { isServer } from '@tanstack/router-core/isServer';
import { Asset } from './Asset';
import { useTags } from './headContentUtils';
import { useRouter } from './useRouter';
function attrsMatch(attrs, element) {
    let expectedAttrCount = 0;
    for (const name in attrs) {
        const value = attrs[name];
        if (value === undefined || value === false || value === null) {
            continue;
        }
        expectedAttrCount++;
        const attrName = name.toLowerCase();
        if (value === true) {
            if (!element.hasAttribute(attrName)) {
                return false;
            }
            continue;
        }
        if (element.getAttribute(attrName) !== String(value)) {
            return false;
        }
    }
    return expectedAttrCount === element.attributes.length;
}
function reconcileHydratedHead(tags, preservedHeadTagElements) {
    if (typeof document === 'undefined') {
        return;
    }
    const matchedHeadElements = new Set();
    const hydratedLinks = document.head.querySelectorAll('link');
    for (const tag of tags) {
        if (tag.tag !== 'link') {
            continue;
        }
        const attrs = tag.attrs;
        const rel = typeof attrs?.rel === 'string' ? attrs.rel.toLowerCase() : undefined;
        if (rel !== 'stylesheet' && rel !== 'preload' && rel !== 'modulepreload') {
            continue;
        }
        for (const element of hydratedLinks) {
            if (!matchedHeadElements.has(element) && attrsMatch(attrs, element)) {
                matchedHeadElements.add(element);
                const key = JSON.stringify(tag);
                (preservedHeadTagElements[key] || (preservedHeadTagElements[key] = [])).push(element);
                break;
            }
        }
    }
}
function cleanupInactivePreservedHeadElements(preservedHeadTagElements, activeElements) {
    for (const key in preservedHeadTagElements) {
        const elements = preservedHeadTagElements[key];
        let nextElements;
        for (const element of elements) {
            if (activeElements.has(element)) {
                ;
                (nextElements || (nextElements = [])).push(element);
            }
            else if (!shouldRemoveInactivePreservedHeadElement(element)) {
                ;
                (nextElements || (nextElements = [])).push(element);
            }
            else {
                element.remove();
            }
        }
        if (nextElements) {
            preservedHeadTagElements[key] = nextElements;
        }
        else {
            delete preservedHeadTagElements[key];
        }
    }
}
function shouldRemoveInactivePreservedHeadElement(element) {
    const rel = element.getAttribute('rel')?.toLowerCase();
    return rel === 'preload' || rel === 'modulepreload';
}
/**
 * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
 * It should be rendered in the `<head>` of your document.
 */
export const HeadContent = Vue.defineComponent({
    name: 'HeadContent',
    props: {
        assetCrossOrigin: {
            type: [String, Object],
            default: undefined,
        },
    },
    setup(props) {
        const router = useRouter();
        const tags = useTags(props.assetCrossOrigin);
        if (isServer ?? router.isServer) {
            return () => {
                return tags().map((tag) => {
                    const key = JSON.stringify(tag);
                    return Vue.h(Asset, {
                        ...tag,
                        key: `tsr-meta-${key}`,
                    });
                });
            };
        }
        const preservedHeadTagElements = {};
        let activePreservedHeadElements = new Set();
        if (router.ssr) {
            reconcileHydratedHead(tags(), preservedHeadTagElements);
        }
        Vue.onUpdated(() => {
            cleanupInactivePreservedHeadElements(preservedHeadTagElements, activePreservedHeadElements);
        });
        Vue.onUnmounted(() => {
            cleanupInactivePreservedHeadElements(preservedHeadTagElements, new Set());
        });
        return () => {
            const renderedPreservedHeadTagKeys = {};
            activePreservedHeadElements = new Set();
            const renderedTags = tags().map((tag) => {
                const key = JSON.stringify(tag);
                const renderedCount = renderedPreservedHeadTagKeys[key] || 0;
                const preservedElement = preservedHeadTagElements[key]?.[renderedCount];
                if (preservedElement?.isConnected) {
                    renderedPreservedHeadTagKeys[key] = renderedCount + 1;
                    activePreservedHeadElements.add(preservedElement);
                    return null;
                }
                return Vue.h(Asset, {
                    ...tag,
                    key: `tsr-meta-${key}`,
                });
            });
            return renderedTags;
        };
    },
});
//# sourceMappingURL=HeadContent.jsx.map