import { useState, useEffect, useCallback } from "react";
const INLINE_AI_TRIGGER_BUTTON_SIZE = 28;
const INLINE_AI_DIALOG_TRIGGER_GAP = 10;
function isRectInViewport(rect) {
    return (rect.top < window.innerHeight &&
        rect.bottom > 0 &&
        rect.left < window.innerWidth &&
        rect.right > 0);
}
/**
 * Calculate position for selection within an input or textarea element.
 * Uses a hidden mirror element to measure text and determine cursor position.
 */
export function getInputSelectionPosition(element, startOffset, endOffset) {
    try {
        const rect = element.getBoundingClientRect();
        const computedStyle = window.getComputedStyle(element);
        // Create a mirror div to measure text position
        const mirror = document.createElement("div");
        mirror.style.position = "absolute";
        mirror.style.visibility = "hidden";
        mirror.style.whiteSpace = element.tagName === "INPUT" ? "pre" : "pre-wrap";
        mirror.style.wordWrap =
            element.tagName === "TEXTAREA" ? "break-word" : "normal";
        mirror.style.font = computedStyle.font;
        mirror.style.fontSize = computedStyle.fontSize;
        mirror.style.fontFamily = computedStyle.fontFamily;
        mirror.style.fontWeight = computedStyle.fontWeight;
        mirror.style.letterSpacing = computedStyle.letterSpacing;
        mirror.style.padding = computedStyle.padding;
        mirror.style.border = computedStyle.border;
        mirror.style.boxSizing = computedStyle.boxSizing;
        mirror.style.width =
            element.tagName === "TEXTAREA" ? `${element.offsetWidth}px` : "auto";
        mirror.style.overflow = "hidden";
        const value = element.value;
        const textBeforeSelection = value.substring(0, startOffset);
        const selectedText = value.substring(startOffset, endOffset);
        // Create text nodes and a span for the selection
        const textBefore = document.createTextNode(textBeforeSelection);
        const selectionSpan = document.createElement("span");
        selectionSpan.textContent = selectedText || "\u200b"; // Zero-width space if empty
        mirror.appendChild(textBefore);
        mirror.appendChild(selectionSpan);
        document.body.appendChild(mirror);
        // Get the position of the selection span
        const spanRect = selectionSpan.getBoundingClientRect();
        const mirrorRect = mirror.getBoundingClientRect();
        // Calculate relative position within the element
        const relativeLeft = spanRect.left - mirrorRect.left;
        const relativeTop = spanRect.top - mirrorRect.top;
        // Account for scroll position in textarea
        const scrollTop = element.tagName === "TEXTAREA"
            ? element.scrollTop
            : 0;
        const scrollLeft = element.tagName === "TEXTAREA"
            ? element.scrollLeft
            : 0;
        // Clean up
        document.body.removeChild(mirror);
        // Calculate absolute position
        const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;
        const paddingTop = parseFloat(computedStyle.paddingTop) || 0;
        const borderLeft = parseFloat(computedStyle.borderLeftWidth) || 0;
        const borderTop = parseFloat(computedStyle.borderTopWidth) || 0;
        const x = rect.left +
            paddingLeft +
            borderLeft +
            relativeLeft +
            spanRect.width / 2 -
            scrollLeft;
        const y = rect.top +
            paddingTop +
            borderTop +
            relativeTop +
            spanRect.height -
            scrollTop;
        return { x, y };
    }
    catch {
        return null;
    }
}
/**
 * Hook to calculate the position for the inline AI trigger/dialog
 * based on the current text selection.
 */
export function useInlineAiPosition(selectedRange) {
    const [position, setPosition] = useState({
        x: 0,
        y: 0,
        visible: false,
    });
    const calculatePosition = useCallback(() => {
        if (!selectedRange?.text) {
            setPosition({ x: 0, y: 0, visible: false });
            return;
        }
        try {
            // First, check if we have an element reference (for input/textarea fields)
            if (selectedRange.element) {
                const element = selectedRange.element;
                // Verify the element is still in the DOM and has the expected selection
                if (document.body.contains(element) &&
                    element.selectionStart !== null) {
                    const elementRect = element.getBoundingClientRect();
                    // Check if element is in viewport
                    if (!isRectInViewport(elementRect)) {
                        setPosition({ x: 0, y: 0, visible: false });
                        return;
                    }
                    const pos = getInputSelectionPosition(element, selectedRange.startOffset, selectedRange.endOffset);
                    if (pos) {
                        setPosition({
                            x: Math.max(20, Math.min(pos.x, window.innerWidth - 220)),
                            y: Math.min(pos.y + 8, window.innerHeight - 100),
                            visible: true,
                        });
                        return;
                    }
                }
            }
            if (selectedRange.clientRect) {
                const rect = selectedRange.clientRect;
                const isVisible = rect.top < window.innerHeight &&
                    rect.bottom > 0 &&
                    rect.left < window.innerWidth &&
                    rect.right > 0;
                if (!isVisible) {
                    setPosition({ x: 0, y: 0, visible: false });
                    return;
                }
                const x = rect.left + rect.width / 2;
                const y = rect.bottom + 8;
                setPosition({
                    x: Math.max(20, Math.min(x, window.innerWidth - 220)),
                    y: Math.min(y, window.innerHeight - 100),
                    visible: true,
                });
                return;
            }
            const selection = window.getSelection();
            if (!selection || selection.isCollapsed) {
                setPosition({ x: 0, y: 0, visible: false });
                return;
            }
            const range = selection.getRangeAt(0);
            const rect = range.getBoundingClientRect();
            // Check if selection is in viewport
            if (!isRectInViewport(rect)) {
                setPosition({ x: 0, y: 0, visible: false });
                return;
            }
            // Position below the selection, centered horizontally
            const x = rect.left + rect.width / 2;
            const y = rect.bottom + 8;
            setPosition({
                x: Math.max(20, Math.min(x, window.innerWidth - 220)),
                y: Math.min(y, window.innerHeight - 100),
                visible: true,
            });
        }
        catch {
            setPosition({ x: 0, y: 0, visible: false });
        }
    }, [
        selectedRange?.text,
        selectedRange?.element,
        selectedRange?.clientRect,
        selectedRange?.startOffset,
        selectedRange?.endOffset,
    ]);
    useEffect(() => {
        calculatePosition();
        // Recalculate on scroll/resize
        const handleUpdate = () => {
            if (selectedRange?.text) {
                calculatePosition();
            }
        };
        window.addEventListener("scroll", handleUpdate, true);
        window.addEventListener("resize", handleUpdate);
        return () => {
            window.removeEventListener("scroll", handleUpdate, true);
            window.removeEventListener("resize", handleUpdate);
        };
    }, [selectedRange?.text, calculatePosition]);
    return position;
}
/**
 * Calculate optimal dialog position near the trigger
 */
export function calculateDialogPosition(triggerPosition, dialogWidth = 190, _dialogHeight = 300, align = "center", anchorOrigin = "trigger") {
    const padding = 16;
    const viewportWidth = window.innerWidth;
    const verticalOffset = anchorOrigin === "trigger"
        ? INLINE_AI_TRIGGER_BUTTON_SIZE + INLINE_AI_DIALOG_TRIGGER_GAP
        : INLINE_AI_DIALOG_TRIGGER_GAP;
    // Position below the trigger button with the requested gap.
    let x = align === "start" ? triggerPosition.x : triggerPosition.x - dialogWidth / 2;
    let y = triggerPosition.y + verticalOffset;
    // Adjust horizontal position if it goes off screen
    if (x < padding) {
        x = padding;
    }
    else if (x + dialogWidth > viewportWidth - padding) {
        x = viewportWidth - dialogWidth - padding;
    }
    // Ensure y is not negative
    y = Math.max(padding, y);
    return { x, y };
}
export default useInlineAiPosition;
//# sourceMappingURL=useInlineAiPosition.js.map