"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from "react";
import { AtSign, Loader2 } from "lucide-react";
import { cn } from "../../lib/utils";
import { Command, CommandEmpty, CommandGroup, CommandItem, CommandList, } from "./command";
import { Popover, PopoverAnchor, PopoverContent } from "./popover";
import { Textarea } from "./textarea";
import { searchUsers, } from "../../editor/services/userService";
const trailingTokenPunctuation = /[,;:.!?\])}'"]$/;
function isAlphaNumeric(value) {
    return /^[a-z0-9]$/i.test(value);
}
function getTextValue(value) {
    if (typeof value === "string")
        return value;
    if (value == null)
        return "";
    return String(value);
}
function getActiveMentionToken(text, selectionStart) {
    if (selectionStart == null || selectionStart < 1)
        return null;
    let start = selectionStart - 1;
    while (start >= 0 && !/\s/.test(text[start] ?? "")) {
        start--;
    }
    start += 1;
    if (text[start] !== "@")
        return null;
    if (start > 0 && isAlphaNumeric(text[start - 1] ?? ""))
        return null;
    const query = text.slice(start + 1, selectionStart);
    if (!query || query.includes("@") || trailingTokenPunctuation.test(query)) {
        return null;
    }
    return {
        start,
        end: selectionStart,
        query,
    };
}
export const MentionTextarea = React.forwardRef(({ className, onChange, onValueChange, onKeyDown, onBlur, onSelect, value, mentionSearchLimit = 8, ...props }, forwardedRef) => {
    const textareaRef = React.useRef(null);
    const [activeMention, setActiveMention] = React.useState(null);
    const [results, setResults] = React.useState([]);
    const [loading, setLoading] = React.useState(false);
    const [activeIndex, setActiveIndex] = React.useState(0);
    const textValue = getTextValue(value);
    const open = !!activeMention && activeMention.query.trim().length >= 2;
    const setTextareaRef = React.useCallback((node) => {
        textareaRef.current = node;
        if (typeof forwardedRef === "function") {
            forwardedRef(node);
        }
        else if (forwardedRef) {
            forwardedRef.current = node;
        }
    }, [forwardedRef]);
    const updateActiveMention = React.useCallback((nextValue) => {
        const textarea = textareaRef.current;
        if (!textarea)
            return;
        const source = nextValue ?? textarea.value;
        setActiveMention(getActiveMentionToken(source, textarea.selectionStart));
    }, []);
    React.useEffect(() => {
        if (!activeMention || activeMention.query.trim().length < 2) {
            setResults([]);
            setLoading(false);
            return;
        }
        let cancelled = false;
        const query = activeMention.query.trim();
        setLoading(true);
        const timer = window.setTimeout(async () => {
            try {
                const users = await searchUsers(query, mentionSearchLimit);
                if (!cancelled) {
                    setResults(users);
                    setActiveIndex(0);
                }
            }
            catch {
                if (!cancelled) {
                    setResults([]);
                }
            }
            finally {
                if (!cancelled) {
                    setLoading(false);
                }
            }
        }, 150);
        return () => {
            cancelled = true;
            window.clearTimeout(timer);
        };
    }, [activeMention?.query, mentionSearchLimit]);
    const commitMention = React.useCallback((user) => {
        if (!activeMention)
            return;
        const textarea = textareaRef.current;
        const currentValue = textarea?.value ?? textValue;
        const mentionText = `@${user.userName}`;
        const nextCharacter = currentValue[activeMention.end] ?? "";
        const spacer = !nextCharacter ||
            (!/\s/.test(nextCharacter) &&
                !trailingTokenPunctuation.test(nextCharacter))
            ? " "
            : "";
        const nextValue = currentValue.slice(0, activeMention.start) +
            mentionText +
            spacer +
            currentValue.slice(activeMention.end);
        const nextSelection = activeMention.start + mentionText.length + spacer.length;
        if (textarea) {
            textarea.value = nextValue;
        }
        onValueChange?.(nextValue);
        setActiveMention(null);
        setResults([]);
        window.requestAnimationFrame(() => {
            textarea?.focus();
            textarea?.setSelectionRange(nextSelection, nextSelection);
        });
    }, [activeMention, onValueChange, textValue]);
    const handleChange = (event) => {
        onChange?.(event);
        onValueChange?.(event.target.value);
        updateActiveMention(event.target.value);
    };
    const handleKeyDown = (event) => {
        if (open) {
            if (event.key === "ArrowDown") {
                event.preventDefault();
                setActiveIndex((current) => results.length === 0 ? 0 : (current + 1) % results.length);
                return;
            }
            if (event.key === "ArrowUp") {
                event.preventDefault();
                setActiveIndex((current) => results.length === 0
                    ? 0
                    : (current - 1 + results.length) % results.length);
                return;
            }
            if ((event.key === "Enter" || event.key === "Tab") &&
                results[activeIndex]) {
                event.preventDefault();
                commitMention(results[activeIndex]);
                return;
            }
            if (event.key === "Escape") {
                event.preventDefault();
                setActiveMention(null);
                return;
            }
        }
        onKeyDown?.(event);
    };
    const handleBlur = (event) => {
        onBlur?.(event);
        window.setTimeout(() => {
            if (document.activeElement !== textareaRef.current) {
                setActiveMention(null);
            }
        }, 120);
    };
    const handleSelect = (event) => {
        onSelect?.(event);
        updateActiveMention();
    };
    return (_jsxs(Popover, { open: open, onOpenChange: (nextOpen) => {
            if (!nextOpen)
                setActiveMention(null);
        }, enableIframeClickDetection: false, children: [_jsx(PopoverAnchor, { asChild: true, children: _jsx(Textarea, { ref: setTextareaRef, className: className, value: value, onChange: handleChange, onKeyDown: handleKeyDown, onKeyUp: () => updateActiveMention(), onClick: () => updateActiveMention(), onSelect: handleSelect, onBlur: handleBlur, ...props }) }), _jsx(PopoverContent, { align: "start", side: "bottom", sideOffset: 4, className: "w-[var(--radix-popover-trigger-width)] min-w-64 p-0", "data-mention-textarea-popover": true, onOpenAutoFocus: (event) => event.preventDefault(), onCloseAutoFocus: (event) => event.preventDefault(), onMouseDown: (event) => event.preventDefault(), children: _jsx(Command, { shouldFilter: false, children: _jsxs(CommandList, { className: "max-h-56", children: [_jsx(CommandEmpty, { children: loading ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx(Loader2, { strokeWidth: 1, className: "h-3.5 w-3.5 animate-spin" }), "Searching"] })) : ("No users found") }), _jsx(CommandGroup, { children: results.map((user, index) => (_jsxs(CommandItem, { value: user.userName, className: cn("items-start gap-2 py-2", index === activeIndex &&
                                        "bg-accent text-accent-foreground"), onMouseEnter: () => setActiveIndex(index), onSelect: () => commitMention(user), children: [_jsx(AtSign, { strokeWidth: 1, className: "mt-0.5 h-3.5 w-3.5 shrink-0" }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-medium", children: user.displayName || user.userName }), _jsx("span", { className: "text-muted-foreground block truncate", children: user.userName })] })] }, user.userName))) })] }) }) })] }));
});
MentionTextarea.displayName = "MentionTextarea";
//# sourceMappingURL=mention-textarea.js.map