import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useCallback, useState, useMemo, useRef, } from "react";
import { useDebouncedCallback } from "use-debounce";
import { useEditContext, useFieldsEditContext } from "../client/editContext";
import { generatePageContext, getCachedContext, } from "../services/contextService";
import { WandSparkles } from "lucide-react";
import { createRoot } from "react-dom/client";
import { LicenseFeatures, useFeature } from "../../licensing";
function InlineCompletionHint({ hintText, isMobile, onAccept, positionStyle, }) {
    return (_jsxs("div", { className: "shadow-[0_4px_14px_rgba(15,23,42,0.14),0_0_0_1px_rgba(15,23,42,0.06)]pointer-events-auto fixed z-95 inline-flex max-w-none cursor-pointer items-center gap-2 rounded-md border border-slate-400 bg-slate-100 px-2.5 py-2 text-xs leading-snug font-medium whitespace-nowrap text-slate-900", style: positionStyle, onClick: isMobile ? onAccept : undefined, role: isMobile ? "button" : undefined, children: [_jsx(WandSparkles, { className: "size-3.5 shrink-0 text-violet-600", strokeWidth: 2, "aria-hidden": true }), _jsx("span", { children: hintText })] }));
}
export function useInlineAiCompletion({ pageViewContext, cursorSpanId, isUpdatingRef, }) {
    const editContext = useEditContext();
    const fieldsContext = useFieldsEditContext();
    const canUseAi = useFeature(LicenseFeatures.AI);
    const [currentCompletion, setCurrentCompletion] = useState(null);
    const [, setIsLoading] = useState(false);
    const abortControllerRef = useRef(null);
    const loadingAnimationRef = useRef(null);
    const applyCompletionRef = useRef(null);
    const hintReactRootRef = useRef(null);
    // Clean up hint element on unmount
    useEffect(() => {
        return () => {
            hintReactRootRef.current?.unmount();
            hintReactRootRef.current = null;
            const hintElement = document.getElementById(`${cursorSpanId}-hint`);
            if (hintElement) {
                hintElement.remove();
            }
            if (loadingAnimationRef.current) {
                cancelAnimationFrame(loadingAnimationRef.current);
            }
        };
    }, [cursorSpanId]);
    const lastCaretPosRef = useRef(null);
    // Simple function to track caret position without inserting spans
    const positionCursorSpan = useCallback(() => {
        if (isUpdatingRef.current)
            return;
        isUpdatingRef.current = true;
        try {
            const iframeWindow = pageViewContext.editorIframe?.contentWindow;
            const iframeDocument = iframeWindow?.document;
            const editableElement = fieldsContext?.inlineEditingFieldElement;
            if (!iframeWindow || !iframeDocument || !editableElement)
                return;
            // Get current selection
            const selection = iframeWindow.getSelection();
            if (!selection || selection.rangeCount === 0)
                return;
            const range = selection.getRangeAt(0);
            // Only proceed if selection is within our editing element
            if (!editableElement.contains(range.commonAncestorContainer))
                return;
            // Save detailed information about the cursor position
            const currentNode = range.startContainer;
            const currentOffset = range.startOffset;
            // Create a temporary range to get text up to cursor
            const tempRange = iframeDocument.createRange();
            tempRange.selectNodeContents(editableElement);
            tempRange.setEnd(currentNode, currentOffset);
            const textUpToCursor = tempRange.toString();
            // Check if cursor position has changed
            const cursorMoved = !lastCaretPosRef.current ||
                lastCaretPosRef.current.node !== currentNode ||
                lastCaretPosRef.current.offset !== currentOffset ||
                textUpToCursor.length !== (lastCaretPosRef.current.textLength || 0);
            if (cursorMoved) {
                // Reset completion if cursor position changed
                lastCaretPosRef.current = {
                    node: currentNode,
                    offset: currentOffset,
                    textLength: textUpToCursor.length,
                };
            }
            // Save a copy of the current range
            const originalRange = range.cloneRange();
            // Remove any existing cursor spans
            const existingSpan = iframeDocument.getElementById(cursorSpanId);
            if (existingSpan) {
                existingSpan.parentNode?.removeChild(existingSpan);
            }
            // Create our cursor span
            const cursorSpan = existingSpan ?? iframeDocument.createElement("span");
            cursorSpan.id = cursorSpanId;
            cursorSpan.style.fontWeight = "bold";
            cursorSpan.style.display = "inline";
            cursorSpan.style.pointerEvents = "none";
            cursorSpan.contentEditable = "false";
            cursorSpan.setAttribute("data-cursor-indicator", "true");
            // Get a working range for insertion
            const workingRange = range.cloneRange();
            workingRange.collapse(true);
            // Insert the span at cursor position
            workingRange.insertNode(cursorSpan);
            // Restore original selection
            selection.removeAllRanges();
            selection.addRange(originalRange);
            // setTimeout(() => {
            //   getCompletionDebounced();
            // }, 100);
        }
        catch (error) {
            console.error("Error updating cursor:", error);
        }
        finally {
            setTimeout(() => {
                isUpdatingRef.current = false;
            }, 10);
        }
    }, [
        pageViewContext.editorIframe?.contentWindow,
        fieldsContext?.inlineEditingFieldElement,
        cursorSpanId,
        isUpdatingRef,
    ]);
    // Extracts the text up to the cursor position in the editable element
    const getContentUpToCursor = useCallback((element) => {
        const iframeWindow = pageViewContext.editorIframe?.contentWindow;
        const selection = iframeWindow?.getSelection();
        if (!element || !selection || selection.rangeCount === 0)
            return null;
        const range = selection.getRangeAt(0);
        const cursorPosition = range.startOffset;
        let contentUpToCursor = "";
        if (element.childNodes.length === 0) {
            contentUpToCursor = "";
        }
        else if (element.childNodes.length === 1 &&
            element.firstChild?.nodeType === Node.TEXT_NODE) {
            const full = element.innerText || "";
            contentUpToCursor = full.substring(0, Math.min(cursorPosition, full.length));
        }
        else {
            const tempRange = document.createRange();
            tempRange.selectNodeContents(element);
            tempRange.setEnd(range.startContainer, range.startOffset);
            contentUpToCursor = tempRange.toString();
        }
        return contentUpToCursor;
    }, [pageViewContext.editorIframe?.contentWindow]);
    // Loading animation with three dots changing color
    const startLoadingAnimation = useCallback(() => {
        const doc = pageViewContext.editorIframe?.contentWindow?.document;
        const span = doc?.getElementById(cursorSpanId);
        if (!doc || !span)
            return;
        span.innerHTML = "";
        span.style.display = "inline-flex";
        span.style.gap = "4px";
        span.style.alignItems = "center";
        for (let i = 0; i < 3; i++) {
            const dot = doc.createElement("span");
            dot.textContent = "•";
            dot.style.transition = "color 0.3s ease";
            dot.style.color = "#ccc";
            dot.style.fontSize = "16px";
            span.appendChild(dot);
        }
        let step = 0;
        const animate = () => {
            const dots = span.querySelectorAll("span");
            dots.forEach((dot, index) => {
                if (index === step % 3) {
                    dot.style.color = "#666";
                }
                else {
                    dot.style.color = "#ccc";
                }
            });
            step++;
            loadingAnimationRef.current = requestAnimationFrame(() => {
                if (step % 15 === 0) {
                    animate();
                }
                else {
                    loadingAnimationRef.current = requestAnimationFrame(animate);
                }
            });
        };
        animate();
    }, [pageViewContext.editorIframe?.contentWindow?.document, cursorSpanId]);
    const stopLoadingAnimation = useCallback(() => {
        if (loadingAnimationRef.current) {
            cancelAnimationFrame(loadingAnimationRef.current);
            loadingAnimationRef.current = null;
        }
    }, []);
    const getCompletion = useCallback(async (element, isManualTrigger = false) => {
        const contentUpToCursor = getContentUpToCursor(element);
        if (!contentUpToCursor?.trim())
            return null;
        if (abortControllerRef.current) {
            abortControllerRef.current.abort();
        }
        abortControllerRef.current = new AbortController();
        const fieldId = element.getAttribute("data-fieldid");
        const itemId = element.getAttribute("data-itemid");
        const language = element.getAttribute("data-language");
        const version = element.getAttribute("data-version");
        if (!fieldId || !itemId || !language || !version)
            return null;
        if (!isManualTrigger) {
            const lastChar = contentUpToCursor.slice(-1);
            if (lastChar !== " " && lastChar !== "\u00A0") {
                return null;
            }
        }
        if (!editContext)
            return null;
        let pageContext = getCachedContext(editContext);
        if (!pageContext) {
            try {
                pageContext = await generatePageContext(editContext, pageViewContext);
            }
            catch (error) {
                console.warn("Failed to generate page context:", error);
            }
        }
        let contextString = "";
        if (pageContext) {
            contextString = `Page Name: ${pageContext.pageTitle} (${pageContext.pageType})\n PageSummary: ${pageContext.abstract}`;
        }
        setIsLoading(true);
        startLoadingAnimation();
        try {
            const endpoint = `/parhelia/agent/GetTextCompletion`;
            const response = await fetch(endpoint, {
                method: "POST",
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded",
                },
                body: new URLSearchParams({
                    textToComplete: contentUpToCursor,
                    contextInfo: contextString,
                }).toString(),
            });
            const data = await response.json();
            return data.completion || null;
        }
        catch (error) {
            if (error instanceof Error && error.name !== "AbortError") {
                console.error("Error getting completion:", error);
            }
            return null;
        }
        finally {
            setIsLoading(false);
            stopLoadingAnimation();
        }
    }, [
        getContentUpToCursor,
        editContext,
        pageViewContext,
        startLoadingAnimation,
        stopLoadingAnimation,
    ]);
    // Debounced AI call: recompute the sentence, call getCompletion, and extract only the "tail" for the ghost text
    const getCompletionDebounced = useDebouncedCallback(async (isManualTrigger = false) => {
        const el = fieldsContext?.inlineEditingFieldElement;
        if (!el)
            return;
        // 1) Recompute the exact sentence at this moment
        const full = getContentUpToCursor(el) || "";
        const sentence = full.split(/[.?!]\s*/).pop() || "";
        // 2) Ask AI for a completion
        const rawSuggestion = await getCompletion(el, isManualTrigger);
        if (!rawSuggestion) {
            setCurrentCompletion(null);
            clearCursorSpan();
            return;
        }
        // 3) Strip off the already-typed sentence to leave just the "completion tail"
        const suggestion = rawSuggestion.startsWith(sentence)
            ? rawSuggestion
            : sentence + rawSuggestion;
        setCurrentCompletion(suggestion);
        updateCursorSpan(suggestion.substring(sentence.length));
    }, 250);
    // Inserts or clears the ghost text inside the cursor span
    const updateCursorSpan = useCallback((text) => {
        const doc = pageViewContext.editorIframe?.contentWindow?.document;
        const span = doc?.getElementById(cursorSpanId);
        if (!doc || !span)
            return;
        // Update the completion text
        if (text) {
            span.textContent = text;
            span.style.color = "#888";
            span.style.fontStyle = "italic";
            // Create or update hint element in the main document
            let hintElement = document.getElementById(`${cursorSpanId}-hint`);
            if (!hintElement) {
                hintElement = document.createElement("div");
                hintElement.id = `${cursorSpanId}-hint`;
                document.body.appendChild(hintElement);
            }
            if (!hintReactRootRef.current) {
                hintElement.replaceChildren();
                hintReactRootRef.current = createRoot(hintElement);
            }
            const hintLabel = editContext?.isMobile
                ? "Tap to accept"
                : "Press Tab to accept ⇥";
            const isMobile = editContext?.isMobile ?? false;
            const iframeRect = pageViewContext.editorIframe?.getBoundingClientRect();
            const spanRect = span.getBoundingClientRect();
            let positionStyle = {
                marginLeft: "0.25rem",
                marginRight: "0.25rem",
            };
            if (iframeRect) {
                if (isMobile) {
                    const centerX = (spanRect.left + spanRect.right) / 2;
                    const gap = 6;
                    positionStyle = {
                        ...positionStyle,
                        left: centerX,
                        top: spanRect.top - gap,
                        transform: "translate(-50%, -100%)",
                    };
                }
                else {
                    const textLength = span.textContent?.length || 0;
                    let left;
                    let top;
                    if (textLength > 0 && span.firstChild) {
                        const range = doc.createRange();
                        range.setStart(span.firstChild, Math.max(0, textLength - 1));
                        range.setEnd(span.firstChild, textLength);
                        const rangeRect = range.getBoundingClientRect();
                        left = iframeRect.left + rangeRect.right;
                        top = iframeRect.top + rangeRect.top;
                    }
                    else {
                        left = iframeRect.left + spanRect.right;
                        top = iframeRect.top + spanRect.top;
                    }
                    positionStyle = {
                        ...positionStyle,
                        left,
                        top,
                        transform: undefined,
                    };
                }
            }
            hintReactRootRef.current.render(_jsx(InlineCompletionHint, { hintText: hintLabel, isMobile: isMobile, onAccept: () => applyCompletionRef.current?.(), positionStyle: positionStyle }));
        }
        else {
            span.textContent = "";
            // Remove hint element if it exists
            const hintElement = document.getElementById(`${cursorSpanId}-hint`);
            if (hintElement) {
                hintReactRootRef.current?.unmount();
                hintReactRootRef.current = null;
                hintElement.remove();
            }
        }
    }, [pageViewContext.editorIframe, cursorSpanId, editContext?.isMobile]);
    const clearCursorSpan = useCallback(() => {
        const doc = pageViewContext.editorIframe?.contentWindow?.document;
        if (!doc)
            return;
        // Clear the completion text
        updateCursorSpan("");
    }, [pageViewContext.editorIframe?.contentWindow?.document, updateCursorSpan]);
    // Handle keydown events for cursor movement (arrow keys, etc.)
    useEffect(() => {
        const keyHandler = (e) => {
            if (e.key === "ArrowLeft" ||
                e.key === "ArrowRight" ||
                e.key === "ArrowUp" ||
                e.key === "ArrowDown" ||
                e.key === " " ||
                e.key === "Tab" ||
                e.key === "End" ||
                e.key === "Backspace" ||
                e.key === "Delete") {
                setCurrentCompletion(null);
                clearCursorSpan();
                setTimeout(() => {
                    if (!isUpdatingRef.current) {
                        positionCursorSpan();
                    }
                }, 10);
                if (e.key === "ArrowRight" || e.key === "Delete") {
                    const cursorSpan = pageViewContext.editorIframe?.contentWindow?.document.getElementById(cursorSpanId);
                    if (cursorSpan) {
                        const originalDisplay = cursorSpan.style.display;
                        cursorSpan.style.display = "none";
                        setTimeout(() => {
                            if (cursorSpan.parentNode) {
                                cursorSpan.style.display = originalDisplay;
                            }
                        }, 0);
                    }
                }
            }
        };
        const doc = pageViewContext.editorIframe?.contentWindow?.document;
        if (!doc)
            return;
        doc.addEventListener("keydown", keyHandler);
        return () => doc.removeEventListener("keydown", keyHandler);
    }, [
        clearCursorSpan,
        cursorSpanId,
        isUpdatingRef,
        pageViewContext.editorIframe?.contentWindow?.document,
        pageViewContext.page,
        positionCursorSpan,
    ]);
    // Function to apply the completion (must be before handleInput)
    const applyCompletion = useCallback(() => {
        const iframeWindow = pageViewContext.editorIframe?.contentWindow;
        const iframeDocument = iframeWindow?.document;
        if (!iframeWindow ||
            !iframeDocument ||
            !fieldsContext?.inlineEditingFieldElement)
            return;
        const cursorSpan = iframeDocument.getElementById(cursorSpanId);
        if (!cursorSpan)
            return;
        const completionToApply = cursorSpan.textContent || "";
        if (!completionToApply)
            return;
        const element = fieldsContext.inlineEditingFieldElement;
        const fieldId = element.getAttribute("data-fieldid");
        const fieldName = element.getAttribute("data-fieldname");
        const itemId = element.getAttribute("data-itemid");
        const language = element.getAttribute("data-language");
        const versionStr = element.getAttribute("data-version");
        const isRichText = element.getAttribute("data-is-richtext") === "true";
        const version = versionStr ? parseInt(versionStr, 10) : undefined;
        if (!fieldId || !itemId || !language || !version)
            return;
        const selection = iframeWindow.getSelection();
        if (!selection || selection.rangeCount === 0)
            return;
        const range = selection.getRangeAt(0);
        const tempRange = document.createRange();
        tempRange.selectNodeContents(element);
        tempRange.setEnd(range.startContainer, range.startOffset);
        const textUpToCursor = tempRange.toString();
        const wordBoundaryRegex = /[\s.,;:!?"'()[\]{}<>/|=+\-*&^%$#@~`](?=[^\s.,;:!?"'()[\]{}<>/|=+\-*&^%$#@~`]*$)/;
        const match = textUpToCursor.match(wordBoundaryRegex);
        const lastWordBoundaryIndex = match && match.index !== undefined ? match.index + 1 : 0;
        const currentPartialWord = textUpToCursor
            .substring(lastWordBoundaryIndex)
            .trim();
        const isOverlapping = currentPartialWord.length > 0 &&
            completionToApply
                .toLowerCase()
                .startsWith(currentPartialWord.toLowerCase());
        if (isOverlapping) {
            const wordRange = document.createRange();
            const startContainer = range.startContainer;
            const startOffset = range.startOffset - currentPartialWord.length;
            if (startOffset >= 0 && startContainer.nodeType === Node.TEXT_NODE) {
                wordRange.setStart(startContainer, startOffset);
                wordRange.setEnd(range.startContainer, range.startOffset);
                wordRange.deleteContents();
            }
            else {
                if (textUpToCursor.length > 0 && !textUpToCursor.endsWith(" ")) {
                    const spaceNode = document.createTextNode(" ");
                    range.insertNode(spaceNode);
                    range.setStartAfter(spaceNode);
                    range.setEndAfter(spaceNode);
                }
            }
        }
        else {
            if (textUpToCursor.length > 0 &&
                !textUpToCursor.endsWith(" ") &&
                !textUpToCursor.endsWith("\n") &&
                !/[.!?\-—:;({[\s]$/.test(textUpToCursor)) {
                const spaceNode = document.createTextNode(" ");
                range.insertNode(spaceNode);
                range.setStartAfter(spaceNode);
                range.setEndAfter(spaceNode);
            }
        }
        const textNode = document.createTextNode(completionToApply);
        range.insertNode(textNode);
        range.setStartAfter(textNode);
        range.setEndAfter(textNode);
        selection.removeAllRanges();
        selection.addRange(range);
        setCurrentCompletion(null);
        clearCursorSpan();
        setTimeout(() => {
            let valueToSave;
            if (isRichText) {
                const clone = element.cloneNode(true);
                const cursorElem = clone.querySelector(`#${cursorSpanId}`);
                if (cursorElem)
                    cursorElem.parentNode?.removeChild(cursorElem);
                const ownerDoc = clone.ownerDocument || document;
                const walker = ownerDoc.createTreeWalker(clone, NodeFilter.SHOW_TEXT);
                const toClean = [];
                while (walker.nextNode()) {
                    const tn = walker.currentNode;
                    if (tn.nodeValue && tn.nodeValue.includes("\u200B"))
                        toClean.push(tn);
                }
                toClean.forEach((tn) => (tn.nodeValue = tn.nodeValue?.replaceAll("\u200B", "") || ""));
                valueToSave = clone.innerHTML;
            }
            else {
                valueToSave = (element.innerText || "").replaceAll("\u200B", "");
            }
            editContext?.operations.editField({
                field: {
                    fieldId,
                    fieldName: fieldName ?? undefined,
                    item: { id: itemId, language, version },
                },
                refresh: "none",
                value: valueToSave,
            });
        }, 0);
    }, [
        pageViewContext.editorIframe?.contentWindow,
        fieldsContext?.inlineEditingFieldElement,
        cursorSpanId,
        clearCursorSpan,
        editContext?.operations,
    ]);
    applyCompletionRef.current = applyCompletion;
    // Manual completion trigger (non-debounced)
    const getCompletionManual = useCallback(async () => {
        if (!canUseAi)
            return;
        const el = fieldsContext?.inlineEditingFieldElement;
        if (!el)
            return;
        const full = getContentUpToCursor(el) || "";
        const sentence = full.split(/[.?!]\s*/).pop() || "";
        const rawSuggestion = await getCompletion(el, true);
        if (!rawSuggestion) {
            setCurrentCompletion(null);
            clearCursorSpan();
            return;
        }
        const suggestion = rawSuggestion.startsWith(sentence)
            ? rawSuggestion
            : sentence + rawSuggestion;
        setCurrentCompletion(suggestion);
        updateCursorSpan(suggestion.substring(sentence.length));
    }, [
        fieldsContext?.inlineEditingFieldElement,
        canUseAi,
        getContentUpToCursor,
        getCompletion,
        clearCursorSpan,
        updateCursorSpan,
    ]);
    // On every input: either reuse the existing suggestion or fire a new one
    const handleInput = useCallback((e) => {
        if (!canUseAi) {
            setCurrentCompletion(null);
            clearCursorSpan();
            return;
        }
        const el = fieldsContext?.inlineEditingFieldElement;
        if (!el)
            return;
        // Clear completion when Escape is pressed
        if (e.key === "Escape") {
            e.preventDefault();
            e.stopPropagation();
            setCurrentCompletion(null);
            clearCursorSpan();
            return;
        }
        // Request new completion when Ctrl+Space is pressed
        if (e.key === " " && (e.ctrlKey || e.metaKey)) {
            e.preventDefault();
            e.stopPropagation();
            setCurrentCompletion(null);
            clearCursorSpan();
            getCompletionManual();
            return;
        }
        // Apply completion when Tab is pressed
        if (e.key === "Tab") {
            // Check if there's an actual completion in the cursor span
            const cursorSpan = pageViewContext.editorIframe?.contentWindow?.document.getElementById(cursorSpanId);
            if (cursorSpan &&
                cursorSpan.textContent &&
                cursorSpan.textContent.trim() !== "") {
                e.preventDefault();
                e.stopPropagation();
                applyCompletion();
                return;
            }
        }
        const full = getContentUpToCursor(el) || "";
        const sentence = full.split(/[.?!]\s*/).pop() || "";
        // If we already have a suggestion, check if the user is still typing along it
        // Normalize spaces to handle both regular and non-breaking spaces
        const normalizedSentence = sentence.replace(/\s/g, " ");
        const normalizedCompletion = currentCompletion?.replace(/\s/g, " ");
        if (normalizedCompletion &&
            normalizedCompletion.startsWith(normalizedSentence)) {
            // user is still matching the suggestion → update the remaining tail
            const remaining = normalizedCompletion.slice(normalizedSentence.length);
            updateCursorSpan(remaining);
            return;
        }
        // else: user diverged → drop it
        setCurrentCompletion(null);
        clearCursorSpan();
        // No active suggestion → fire new request once they've typed 2+ words
        const words = sentence.trim().split(/\s+/).filter(Boolean);
        // Check if cursor is at the end of the text
        const isAtEnd = () => {
            const el = fieldsContext?.inlineEditingFieldElement;
            if (!el)
                return false;
            const iframeWindow = pageViewContext.editorIframe?.contentWindow;
            const selection = iframeWindow?.getSelection();
            if (!selection || selection.rangeCount === 0)
                return false;
            const range = selection.getRangeAt(0);
            // Create a range for the whole editable element
            const fullRange = document.createRange();
            fullRange.selectNodeContents(el);
            // Get the full text content
            const fullText = el.textContent || "";
            // Get text up to cursor
            const tempRange = document.createRange();
            tempRange.selectNodeContents(el);
            tempRange.setEnd(range.startContainer, range.startOffset);
            const textUpToCursor = tempRange.toString();
            // Cursor is at the end if the text up to cursor equals the full text
            // (accounting for whitespace differences)
            return (textUpToCursor.trim() === fullText.trim() ||
                (fullText.trim().startsWith(textUpToCursor.trim()) &&
                    fullText.trim().length === textUpToCursor.trim().length));
        };
        if (words.length >= 2 && isAtEnd()) {
            getCompletionDebounced();
        }
        else {
            setCurrentCompletion(null);
            clearCursorSpan();
        }
    }, [
        fieldsContext?.inlineEditingFieldElement,
        getContentUpToCursor,
        currentCompletion,
        canUseAi,
        clearCursorSpan,
        getCompletionManual,
        pageViewContext.editorIframe?.contentWindow,
        cursorSpanId,
        applyCompletion,
        updateCursorSpan,
        getCompletionDebounced,
    ]);
    // Wire up the input listener
    useEffect(() => {
        if (!canUseAi || !editContext?.enableCompletions)
            return;
        const el = fieldsContext?.inlineEditingFieldElement;
        if (!el)
            return;
        el.addEventListener("keydown", handleInput);
        return () => el.removeEventListener("keydown", handleInput);
    }, [
        fieldsContext?.inlineEditingFieldElement,
        handleInput,
        canUseAi,
        editContext?.enableCompletions,
    ]);
    // Add mouse click handler to update cursor span position
    useEffect(() => {
        if (!canUseAi || !editContext?.enableCompletions)
            return;
        const el = fieldsContext?.inlineEditingFieldElement;
        if (!el)
            return;
        const handleMouseUp = () => {
            setTimeout(() => {
                if (!isUpdatingRef.current) {
                    positionCursorSpan();
                    // Clear existing completion when cursor position changes via mouse
                    setCurrentCompletion(null);
                    clearCursorSpan();
                }
            }, 10);
        };
        el.addEventListener("mouseup", handleMouseUp);
        return () => el.removeEventListener("mouseup", handleMouseUp);
    }, [
        fieldsContext?.inlineEditingFieldElement,
        canUseAi,
        editContext?.enableCompletions,
        isUpdatingRef,
        positionCursorSpan,
        clearCursorSpan,
    ]);
    // Clean up abort controller on unmount
    useEffect(() => {
        return () => {
            if (abortControllerRef.current) {
                abortControllerRef.current.abort();
                abortControllerRef.current = null;
            }
            if (loadingAnimationRef.current) {
                cancelAnimationFrame(loadingAnimationRef.current);
                loadingAnimationRef.current = null;
            }
        };
    }, []);
    // Exposed manual trigger (if needed)
    return useMemo(() => () => {
        setCurrentCompletion(null);
        clearCursorSpan();
        if (canUseAi) {
            getCompletionManual();
        }
    }, [canUseAi, clearCursorSpan, getCompletionManual]);
}
//# sourceMappingURL=useInlineAICompletion.js.map