import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React from "react";
import { Check, Copy, Download, Loader2, Search } from "lucide-react";
import { Button } from "../../components/ui/button";
import { Input } from "../../components/ui/input";
import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
import { cn } from "../../lib/utils";
import { SimpleTabs } from "../ui/SimpleTabs";
function escapeRegExp(value) {
    return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function HighlightedPre({ text, query, activeOccurrenceIndex, className, }) {
    const preRef = React.useRef(null);
    const content = React.useMemo(() => {
        const q = query.trim();
        if (!q)
            return text;
        const matches = [];
        const r = new RegExp(`(${escapeRegExp(q)})`, "gi");
        let m;
        while ((m = r.exec(text)) !== null) {
            matches.push({ start: m.index, end: m.index + m[0].length });
        }
        if (matches.length === 0) {
            return text;
        }
        const mc = matches.length;
        const safeIdx = ((activeOccurrenceIndex % mc) + mc) % mc;
        const nodes = [];
        let last = 0;
        matches.forEach((pos, i) => {
            if (pos.start > last) {
                nodes.push(text.slice(last, pos.start));
            }
            nodes.push(_jsx("mark", { "data-occurrence-index": i, className: cn("rounded-sm px-0 text-inherit", i === safeIdx
                    ? "bg-feedback-orange/70 ring-feedback-orange/90 ring-1"
                    : "bg-feedback-orange/35"), children: text.slice(pos.start, pos.end) }, `${pos.start}-${i}`));
            last = pos.end;
        });
        if (last < text.length) {
            nodes.push(text.slice(last));
        }
        return nodes;
    }, [text, query, activeOccurrenceIndex]);
    React.useLayoutEffect(() => {
        const q = query.trim();
        const root = preRef.current;
        if (!q || !root)
            return;
        const marks = root.querySelectorAll("mark[data-occurrence-index]");
        if (marks.length === 0)
            return;
        const n = marks.length;
        const safeIdx = ((activeOccurrenceIndex % n) + n) % n;
        const el = root.querySelector(`mark[data-occurrence-index="${safeIdx}"]`);
        el?.scrollIntoView({ block: "nearest", behavior: "smooth" });
    }, [text, query, activeOccurrenceIndex]);
    const q = query.trim();
    return (_jsx("pre", { ref: preRef, className: className, children: q ? content : text }));
}
function countMatches(text, query) {
    const q = query.trim();
    if (!q)
        return 0;
    const re = new RegExp(escapeRegExp(q), "gi");
    return [...text.matchAll(re)].length;
}
export function ContentInspectorPopover({ title, trigger, sections, loadSections, emptyMessage = "No content available.", className, align = "end", side = "bottom", downloadFileName, }) {
    const [open, setOpen] = React.useState(false);
    const [loadedSections, setLoadedSections] = React.useState(sections ?? []);
    const [isLoading, setIsLoading] = React.useState(false);
    const [loadError, setLoadError] = React.useState(null);
    const [copiedMode, setCopiedMode] = React.useState(null);
    const [activeTab, setActiveTab] = React.useState(0);
    const [searchQuery, setSearchQuery] = React.useState("");
    const [activeOccurrenceIndex, setActiveOccurrenceIndex] = React.useState(0);
    const searchInputRef = React.useRef(null);
    const loadSectionsRef = React.useRef(loadSections);
    React.useEffect(() => {
        loadSectionsRef.current = loadSections;
    }, [loadSections]);
    React.useEffect(() => {
        if (sections) {
            setLoadedSections(sections);
        }
    }, [sections]);
    React.useEffect(() => {
        if (!open) {
            setSearchQuery("");
            setActiveOccurrenceIndex(0);
        }
    }, [open]);
    React.useEffect(() => {
        setActiveOccurrenceIndex(0);
    }, [searchQuery]);
    React.useEffect(() => {
        setActiveOccurrenceIndex(0);
    }, [activeTab]);
    React.useEffect(() => {
        if (!open || !loadSectionsRef.current)
            return;
        let cancelled = false;
        setIsLoading(true);
        setLoadError(null);
        loadSectionsRef
            .current()
            .then((nextSections) => {
            if (!cancelled) {
                setLoadedSections(nextSections ?? []);
            }
        })
            .catch((error) => {
            if (!cancelled) {
                setLoadError(error instanceof Error ? error.message : "Failed to load content.");
                setLoadedSections([]);
            }
        })
            .finally(() => {
            if (!cancelled) {
                setIsLoading(false);
            }
        });
        return () => {
            cancelled = true;
        };
    }, [open]);
    React.useEffect(() => {
        if (!copiedMode)
            return;
        const timeoutId = window.setTimeout(() => setCopiedMode(null), 1500);
        return () => window.clearTimeout(timeoutId);
    }, [copiedMode]);
    const displaySections = React.useMemo(() => loadedSections, [loadedSections]);
    const activeSection = displaySections[Math.min(activeTab, Math.max(displaySections.length - 1, 0))];
    React.useEffect(() => {
        if (activeTab >= displaySections.length) {
            setActiveTab(0);
        }
    }, [activeTab, displaySections.length]);
    const activeMatchCount = React.useMemo(() => {
        if (activeSection?.contentNode)
            return 0;
        const c = activeSection?.content;
        if (!c?.trim())
            return 0;
        return countMatches(c, searchQuery);
    }, [activeSection?.content, activeSection?.contentNode, searchQuery]);
    const activeSectionSupportsSearch = Boolean(activeSection?.content?.trim()) && !activeSection?.contentNode;
    const formatSectionCopyText = React.useCallback((section) => `--- ${section.title.toUpperCase()} ---\n${section.content?.trim() ? section.content : emptyMessage}`, [emptyMessage]);
    const copyText = React.useMemo(() => (activeSection ? formatSectionCopyText(activeSection) : ""), [activeSection, formatSectionCopyText]);
    const copyAllText = React.useMemo(() => displaySections.length > 0
        ? displaySections
            .map((section) => formatSectionCopyText(section))
            .join("\n\n")
        : "", [displaySections, formatSectionCopyText]);
    const handleCopy = React.useCallback(async () => {
        if (!copyText)
            return;
        try {
            await navigator.clipboard.writeText(copyText);
            setCopiedMode("active");
        }
        catch (error) {
            console.error("Failed to copy inspector content:", error);
        }
    }, [copyText]);
    const handleCopyAll = React.useCallback(async () => {
        if (!copyAllText)
            return;
        try {
            await navigator.clipboard.writeText(copyAllText);
            setCopiedMode("all");
        }
        catch (error) {
            console.error("Failed to copy inspector content:", error);
        }
    }, [copyAllText]);
    const handleDownloadAll = React.useCallback(() => {
        if (!copyAllText || !downloadFileName)
            return;
        try {
            const blob = new Blob([copyAllText], {
                type: "text/plain;charset=utf-8",
            });
            const url = URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = downloadFileName;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
        }
        catch (error) {
            console.error("Failed to download inspector content:", error);
        }
    }, [copyAllText, downloadFileName]);
    const goToNextOccurrence = React.useCallback(() => {
        if (activeSection?.contentNode)
            return;
        const c = activeSection?.content;
        const q = searchQuery.trim();
        if (!c?.trim() || !q)
            return;
        const n = countMatches(c, q);
        if (n === 0)
            return;
        setActiveOccurrenceIndex((i) => (i + 1) % n);
    }, [activeSection?.content, activeSection?.contentNode, searchQuery]);
    const handleFindShortcut = React.useCallback((e) => {
        if (!(e.ctrlKey || e.metaKey) || e.key !== "f")
            return;
        e.preventDefault();
        e.stopPropagation();
        const input = searchInputRef.current;
        const searchWasFocused = document.activeElement === input;
        input?.focus();
        input?.select();
        if (activeSection?.contentNode)
            return;
        const q = searchQuery.trim();
        const c = activeSection?.content;
        if (!q || !c?.trim())
            return;
        const n = countMatches(c, q);
        if (n === 0)
            return;
        if (searchWasFocused) {
            setActiveOccurrenceIndex((i) => (i + 1) % n);
        }
    }, [searchQuery, activeSection?.content, activeSection?.contentNode]);
    const renderSectionBody = React.useCallback((section) => {
        if (section.contentNode) {
            return (_jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: section.contentNode }));
        }
        if (section.content?.trim()) {
            return (_jsx(HighlightedPre, { text: section.content, query: searchQuery, activeOccurrenceIndex: activeOccurrenceIndex, className: "bg-neutral-grey-100 text-neutral-grey-5 min-h-0 flex-1 overflow-auto rounded px-3 py-3 font-mono text-[11px] leading-5 break-all whitespace-pre-wrap" }));
        }
        return (_jsx("div", { className: "border-border-default bg-neutral-grey-5 text-neutral-grey-50 flex min-h-0 flex-1 items-center justify-center rounded border border-dashed px-3 py-3 text-xs", children: emptyMessage }));
    }, [activeOccurrenceIndex, emptyMessage, searchQuery]);
    return (_jsxs(Popover, { open: open, onOpenChange: setOpen, enableIframeClickDetection: false, children: [_jsx(PopoverTrigger, { asChild: true, children: trigger }), _jsxs(PopoverContent, { align: align, side: side, onKeyDownCapture: handleFindShortcut, className: cn("w-[min(44rem,calc(100vw-2rem))] max-w-[calc(100vw-2rem)] p-0", className), children: [_jsxs("div", { className: "space-y-2 border-b px-3 py-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: title }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs(Button, { type: "button", size: "xxs", variant: "ghost", onClick: handleCopy, disabled: !copyText || isLoading, className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100", children: [copiedMode === "active" ? (_jsx(Check, { className: "h-3 w-3", strokeWidth: 1.5 })) : (_jsx(Copy, { className: "h-3 w-3", strokeWidth: 1.5 })), copiedMode === "active" ? "Copied tab" : "Copy tab"] }), _jsxs(Button, { type: "button", size: "xxs", variant: "ghost", onClick: handleCopyAll, disabled: !copyAllText || isLoading, className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100", children: [copiedMode === "all" ? (_jsx(Check, { className: "h-3 w-3", strokeWidth: 1.5 })) : (_jsx(Copy, { className: "h-3 w-3", strokeWidth: 1.5 })), copiedMode === "all" ? "Copied all" : "Copy all"] }), downloadFileName ? (_jsxs(Button, { type: "button", size: "xxs", variant: "ghost", onClick: handleDownloadAll, disabled: !copyAllText || isLoading, className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100", children: [_jsx(Download, { className: "h-3 w-3", strokeWidth: 1.5 }), "Download"] })) : null] })] }), !isLoading && !loadError && activeSectionSupportsSearch && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "relative min-w-0 flex-1", children: [_jsx(Search, { className: "text-neutral-grey-50 pointer-events-none absolute top-1/2 left-2 h-3 w-3 -translate-y-1/2", strokeWidth: 1.5, "aria-hidden": true }), _jsx(Input, { ref: searchInputRef, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyDown: (e) => {
                                                    if (e.key === "Enter") {
                                                        e.preventDefault();
                                                        goToNextOccurrence();
                                                    }
                                                }, placeholder: "Find in content\u2026", className: "border-border-default h-7 pr-2 pl-7 text-[11px]", "aria-label": "Find in content" })] }), searchQuery.trim() ? (_jsx("span", { className: "text-neutral-grey-50 shrink-0 text-[10px] tabular-nums", children: activeMatchCount === 0
                                            ? "No matches"
                                            : `${activeMatchCount} match${activeMatchCount === 1 ? "" : "es"}` })) : null] }))] }), _jsx("div", { className: "h-112 overflow-hidden p-3", children: isLoading ? (_jsxs("div", { className: "text-neutral-grey-50 flex h-full items-center gap-2 text-xs", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin", strokeWidth: 1.5 }), "Loading..."] })) : loadError ? (_jsx("div", { className: "border-feedback-red bg-feedback-red-light text-feedback-red rounded border px-3 py-2 text-xs", children: loadError })) : displaySections.length > 0 ? (displaySections.length === 1 ? (_jsxs("div", { className: "flex h-full flex-col space-y-1", children: [_jsx("div", { className: "text-neutral-grey-100 shrink-0 text-[11px] font-medium", children: displaySections[0].title }), renderSectionBody(displaySections[0])] })) : (_jsx(SimpleTabs, { tabs: displaySections.map((section) => ({
                                id: section.title,
                                label: section.title,
                                content: (_jsx("div", { className: "flex h-full min-h-0 flex-col pt-2", children: renderSectionBody(section) })),
                            })), activeTab: activeTab, setActiveTab: setActiveTab, className: "justify-start gap-0 border-b" }))) : (_jsx("div", { className: "text-neutral-grey-50 flex h-full items-center justify-center text-xs", children: emptyMessage })) })] })] }));
}
//# sourceMappingURL=ContentInspectorPopover.js.map