<script setup lang="ts">
import type { MarkdownRoot, ParsedContent, TocLink } from '@nuxt/content/dist/runtime/types';
import type { Canvas, CanvasContent } from '~/types/canvas';

interface ParsedContentExtended extends Omit<ParsedContent, 'body'> {
    body: MarkdownRoot | CanvasContent | null;
}

const props = defineProps({
    href: {
        type: String,
        default: ''
    },
    target: {
        type: String,
        default: undefined,
        required: false
    }
})

function sluggify(s: string): string {
    return s
        .split("/")
        .map((segment) => segment.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/^\d\. */g, '').replace(/\s/g, "-").replace(/%/g, "-percent").replace(/\?/g, "-q").toLowerCase()) // slugify all segments
        .filter(e => !!e)
        .join("/") // always use / as sep
        .replace(/\/$/, "")
}
function flatten(val: TocLink[]): TocLink[] {
    return val.flatMap ? val?.flatMap((e: TocLink) => e.children ? [e, ...flatten(e.children)] : e) : val;
}

const link = (props.href.includes('#') ? props.href.substring(0, props.href.indexOf('#')) : props.href).replace(/\..*$/, '');
const anchor = props.href.includes('#') ? props.href.substring(props.href.indexOf('#'), props.href.length) : '';
let content = ref<ParsedContentExtended>(), loading = ref(true);

queryContent().where({ _path: new RegExp("/" + sluggify(link) + '$', 'i') }).findOne().then((result: ParsedContentExtended) => {
    content.value = result;
    loading.value = false;
    let body = result.body;

    if(anchor && result && body)
    {
        if(result._type == 'markdown' && (body as MarkdownRoot).children)
        {
            body = body as MarkdownRoot;
            const id = flatten(body?.toc?.links ?? []).find(e => "#" + sluggify(e.id) === anchor);
            const tag = `h${id?.depth ?? 0}`;

            const startIdx = body.children.findIndex(e => e.tag === tag && e?.props?.id === id?.id) ?? 0;
            const nbr = body.children.findIndex((e, i) => i > startIdx && e.tag?.match(new RegExp(`h[1-${id?.depth ?? 1}]`)));

            body.children = body.children.splice(startIdx, (nbr === -1 ? body.children.length : nbr) - startIdx);
        }
        else if(result._type == 'canvas')
        {
            body = body as CanvasContent;
            const nodes = body?.groups?.find(e => "#" + sluggify(e.name) === anchor)?.nodes;

            body.nodes = body.nodes.filter(e => nodes?.includes(e.id));
            body.edges = body.edges.filter(e => nodes?.includes(e.fromNode) && nodes?.includes(e.toNode));
        }
    }
}).catch(() => {
    loading.value = false;
});

const hovered = ref(false), pos = ref<any>();
let timeout: NodeJS.Timeout;
function showPreview(e: Event, bbox: boolean) {
    clearTimeout(timeout);
    if(bbox)
    {
        const target = e.currentTarget as HTMLElement;
        const rect = target?.getBoundingClientRect();
        const r: any = {};
        if(rect.bottom + 450 < window.innerHeight)
            r.top = (rect.bottom + 4) + "px";
        else
            r.bottom = (window.innerHeight - rect.top + 4) + "px";
        if(rect.right + 550 < window.innerWidth)
            r.left = rect.left + "px";
        else
            r.right = (window.innerWidth - rect.left + 4) + "px";
        pos.value = r;
    }
    hovered.value = true;
}
function hidePreview(e: Event) {
    timeout = setTimeout(() => hovered.value = false, 300);
}
</script>

<template >
    <NuxtLink custom no-prefetch v-slot="{ href: hrefSlot, navigate }" :to="(content?._path ?? link + anchor) ?? href" :target="target">
        <a :href="hrefSlot" @click="navigate" @mouseenter="(e) => showPreview(e, true)" @mouseleave="hidePreview" v-bind="$attrs"><slot ></slot></a>
    </NuxtLink>
    <Teleport to="body" v-if="hovered && (loading || !!content)">
        <div class="popover hover-popover is-loaded" :style="pos" @mouseenter="(e) => showPreview(e, false)" @mouseleave="hidePreview">
            <template v-if="!!content">
                <div class="markdown-embed" v-if="content._type == 'markdown' && ((content as ParsedContent)?.body?.children?.length ?? 0) > 0">
                    <div class="markdown-embed-content">
                        <div class="markdown-preview-view markdown-rendered node-insert-event hide-title">
                            <div class="markdown-preview-sizer markdown-preview-section" style="padding-bottom: 0px;">
                                <h1 v-if="content?.title">{{ content?.title }}</h1>
                                <ContentRenderer :key="content._id" :value="content"/>
                            </div>
                        </div>
                    </div>
                </div>
                <div v-else-if="content._type == 'canvas'" class="canvas-embed is-loaded">
                    <CanvasRenderer :key="content._id" :canvas="(content as Canvas)" />
                </div>
                <div class="markdown-embed" v-else>
                    <div class="not-found-container">
                        <div class="not-found-image"></div>
                        <div class="not-found-title">Impossible de prévisualiser</div>
                        <div class="not-found-description">Cliquez sur le lien pour accéder au contenu</div>
                    </div>
                </div>
            </template>
            <div v-else>

            </div>
        </div>
    </Teleport>
</template>