import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
import { Check, ChevronDown } from "lucide-react";
import { Button } from "../../../../components/ui/button";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "../../../../components/ui/command";
import { Popover, PopoverContent, PopoverTrigger, } from "../../../../components/ui/popover";
import { cn } from "../../../../lib/utils";
export function handleProfileSwitcherFocusOutside(event, keyboardFocusExitRequested) {
    if (keyboardFocusExitRequested)
        return false;
    event.preventDefault();
    return true;
}
function AgentProfileRowContent({ profile, selected, }) {
    const title = profile.displayTitle || profile.name;
    return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [_jsx("span", { className: "font-normal whitespace-normal", children: title }), profile.description ? (_jsx("div", { className: "text-neutral-grey-50 line-clamp-2 text-[10px] leading-tight whitespace-normal opacity-90", children: profile.description })) : null] }), _jsx(Check, { className: cn("mt-0.5 size-4 shrink-0", selected ? "opacity-100" : "opacity-0"), strokeWidth: 1 })] }));
}
/**
 * Groups selectable profiles by category, ordered by the smallest
 * categoryOrder within each group; uncategorized profiles come last.
 * Hidden profiles stay selectable when they are current or the default,
 * so the (hidden-by-default) Parhelia profile remains reachable after
 * switching away from it.
 */
export function getSwitchableProfileGroups(profiles, currentProfileId) {
    const visible = profiles.filter((profile) => !profile.hiddenFromOverview ||
        profile.id === currentProfileId ||
        profile.isDefault);
    const groups = new Map();
    for (const profile of visible) {
        const key = profile.category || "";
        const order = profile.category != null && profile.categoryOrder != null
            ? profile.categoryOrder
            : Number.MAX_SAFE_INTEGER;
        const group = groups.get(key);
        if (group) {
            group.profiles.push(profile);
            group.order = Math.min(group.order, order);
        }
        else {
            groups.set(key, {
                category: profile.category || undefined,
                order,
                profiles: [profile],
            });
        }
    }
    return [...groups.values()].sort((a, b) => {
        // Uncategorized always last, then by order, then by name.
        if (!a.category !== !b.category)
            return a.category ? -1 : 1;
        if (a.order !== b.order)
            return a.order - b.order;
        return (a.category || "").localeCompare(b.category || "");
    });
}
/**
 * "Looking for a specialist?" popover on the new-chat greeting: switches a
 * draft agent to a different profile before the session starts.
 */
export function AgentProfileSwitcher({ profiles, currentProfileId, onSelectProfile, disabled, }) {
    const [open, setOpen] = useState(false);
    const [portalContainer, setPortalContainer] = useState(null);
    const [highlightedProfileId, setHighlightedProfileId] = useState(currentProfileId || "");
    const [searchQuery, setSearchQuery] = useState("");
    const triggerRef = useRef(null);
    const selectedProfileRef = useRef(null);
    const keyboardFocusExitRef = useRef(false);
    const keyboardFocusExitResetRef = useRef(null);
    const groups = useMemo(() => getSwitchableProfileGroups(profiles, currentProfileId), [profiles, currentProfileId]);
    const currentProfile = useMemo(() => profiles.find((profile) => profile.id === currentProfileId), [profiles, currentProfileId]);
    const triggerLabel = currentProfile && !currentProfile.isDefault
        ? currentProfile.displayTitle || currentProfile.name
        : "Looking for a specialist?";
    useEffect(() => {
        setHighlightedProfileId(currentProfileId || "");
    }, [currentProfileId]);
    useLayoutEffect(() => {
        if (!open)
            return;
        selectedProfileRef.current?.scrollIntoView({ block: "nearest" });
    }, [open, currentProfileId]);
    useEffect(() => () => {
        if (keyboardFocusExitResetRef.current !== null) {
            window.clearTimeout(keyboardFocusExitResetRef.current);
        }
    }, []);
    const handleContentKeyDownCapture = useCallback((event) => {
        if (event.key !== "Tab")
            return;
        // Focus leaving through Tab/Shift+Tab is deliberate and keeps Radix's
        // normal keyboard dismissal. Clear the one-shot permission after the
        // browser has applied the key's default focus movement.
        keyboardFocusExitRef.current = true;
        if (keyboardFocusExitResetRef.current !== null) {
            window.clearTimeout(keyboardFocusExitResetRef.current);
        }
        keyboardFocusExitResetRef.current = window.setTimeout(() => {
            keyboardFocusExitRef.current = false;
            keyboardFocusExitResetRef.current = null;
        }, 0);
    }, []);
    const handleFocusOutside = useCallback((event) => {
        const keyboardFocusExitRequested = keyboardFocusExitRef.current;
        keyboardFocusExitRef.current = false;
        if (keyboardFocusExitResetRef.current !== null) {
            window.clearTimeout(keyboardFocusExitResetRef.current);
            keyboardFocusExitResetRef.current = null;
        }
        handleProfileSwitcherFocusOutside(event, keyboardFocusExitRequested);
    }, []);
    const handleOpenChange = useCallback((nextOpen) => {
        if (nextOpen && triggerRef.current) {
            setPortalContainer(triggerRef.current.closest('[data-slot="dialog-content"]'));
            setHighlightedProfileId(currentProfileId || "");
            setSearchQuery("");
        }
        setOpen(nextOpen);
    }, [currentProfileId]);
    const handleSelect = useCallback((profileId) => {
        if (profileId === currentProfileId) {
            setOpen(false);
            return;
        }
        // Keep the menu open until an asynchronous profile change has finished.
        // Closing it first lets the composer become interactive while the draft
        // still carries its previous profile, so an immediate submit can start
        // the agent with that stale profile.
        const selection = onSelectProfile(profileId);
        if (selection && typeof selection.then === "function") {
            void Promise.resolve(selection)
                .then(() => setOpen(false))
                .catch((error) => {
                console.error("Failed to switch agent profile", error);
            });
            return;
        }
        setOpen(false);
    }, [currentProfileId, onSelectProfile]);
    if (groups.length === 0)
        return null;
    return (_jsxs(Popover, { open: open, onOpenChange: handleOpenChange, enableIframeClickDetection: false, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ref: triggerRef, variant: "ghost", size: "xs", disabled: disabled, "data-testid": "agent-greeting-profile-switcher", className: "text-neutral-grey-50 hover:text-neutral-grey-100 gap-1 text-xs font-normal", "aria-expanded": open, children: [triggerLabel, _jsx(ChevronDown, { strokeWidth: 1, className: "text-neutral-grey-50 size-3 shrink-0" })] }) }), _jsx(PopoverContent, { className: "w-[320px] p-0 text-xs", align: "center", sideOffset: 4, container: portalContainer, 
                // Editor hydration can move focus through the document body or an
                // iframe without a stable focus target. Dismiss on explicit user
                // intent (pointer outside, Escape, or Tab), not on that programmatic
                // focus churn while a profile is being selected.
                onFocusOutside: handleFocusOutside, onKeyDownCapture: handleContentKeyDownCapture, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: _jsxs(Command, { className: "w-full", value: highlightedProfileId, onValueChange: setHighlightedProfileId, children: [_jsx(CommandInput, { placeholder: "Search agents...", value: searchQuery, onValueChange: setSearchQuery }), _jsxs(CommandList, { className: "max-h-[320px] w-full", children: [_jsx(CommandEmpty, { children: "No agents found." }), groups.map((group) => (_jsx(CommandGroup, { heading: group.category, children: group.profiles.map((profile) => {
                                        const isCurrent = profile.id === currentProfileId;
                                        return (_jsx(CommandItem, { ref: isCurrent ? selectedProfileRef : undefined, value: profile.id, keywords: [
                                                profile.name,
                                                profile.displayTitle || "",
                                                profile.description || "",
                                            ].filter(Boolean), onSelect: () => handleSelect(profile.id), "data-testid": "agent-profile-switcher-option", "data-profile-id": profile.id, onPointerLeave: () => {
                                                // cmdk automatically highlights the first filtered
                                                // result. Resetting to a current profile that has been
                                                // filtered out makes it immediately select the result
                                                // again, which continuously moves/remounts the row
                                                // under the pointer and can make it impossible to
                                                // click. Preserve the filtered highlight until the
                                                // query is cleared.
                                                if (!searchQuery) {
                                                    setHighlightedProfileId(currentProfileId || "");
                                                }
                                            }, className: cn("data-[selected=true]:bg-neutral-grey-5 data-[selected=true]:text-neutral-grey-100 flex items-start justify-between gap-3 p-2", isCurrent && "bg-neutral-grey-5 text-neutral-grey-100"), children: _jsx(AgentProfileRowContent, { profile: profile, selected: isCurrent }) }, profile.id));
                                    }) }, group.category || "__other")))] })] }) })] }));
}
//# sourceMappingURL=AgentProfileSwitcher.js.map