"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useId, useMemo, useRef, useState } from "react";
import { cn } from "@stigmer/theme";
import { getUserMessage } from "@stigmer/sdk";
import { useResourceAccess } from "./useResourceAccess.js";
import { ProviderBadge, providerLabel } from "./ProviderBadge.js";
/**
 * Accessible combobox for picking an organization member to share with.
 *
 * Replaces raw account-ID entry: users type a name or email and choose a
 * person from the org's member list. Because email is not unique across
 * identity sources, each candidate shows a {@link ProviderBadge} so accounts
 * that share an email (e.g. a direct account and a federated one) can be told
 * apart. The resolved `identity_account` ID is carried internally — the user
 * never sees it.
 *
 * Members who already have access are shown disabled, so the same person is
 * not granted twice.
 *
 * Search is over the org member list the caller can already see
 * (`listResourceAccessByPrincipal` on the organization), so it introduces no
 * new account-enumeration surface.
 *
 * All visual properties flow through `--stgm-*` design tokens.
 */
export function PrincipalPicker({ orgId, value, onChange, excludePrincipalIds, disabled = false, className, }) {
    const listboxId = useId();
    const { members, isLoading, error } = useResourceAccess(orgId ? { kind: "organization", id: orgId } : null);
    const [query, setQuery] = useState("");
    const [open, setOpen] = useState(false);
    const [activeIndex, setActiveIndex] = useState(0);
    const inputRef = useRef(null);
    const excluded = useMemo(() => new Set(excludePrincipalIds ?? []), [excludePrincipalIds]);
    // Org members that are identity accounts, deduped by ID. The org list groups
    // by principal, so each ID appears once already; the dedupe guards against
    // inherited-role duplicates.
    const candidates = useMemo(() => {
        const byId = new Map();
        for (const entry of members) {
            const p = entry.principal;
            if (!p || p.kind !== "identity_account" || !p.id)
                continue;
            if (!byId.has(p.id))
                byId.set(p.id, p);
        }
        return [...byId.values()];
    }, [members]);
    // Emails that appear on more than one candidate — these are the rows where
    // the provider badge is doing real disambiguation work.
    const duplicatedEmails = useMemo(() => {
        const counts = new Map();
        for (const c of candidates) {
            const email = c.email?.toLowerCase();
            if (email)
                counts.set(email, (counts.get(email) ?? 0) + 1);
        }
        return new Set([...counts.entries()].filter(([, n]) => n > 1).map(([email]) => email));
    }, [candidates]);
    const filtered = useMemo(() => {
        const q = query.trim().toLowerCase();
        if (!q)
            return candidates;
        return candidates.filter((c) => {
            const name = (c.name ?? "").toLowerCase();
            const email = (c.email ?? "").toLowerCase();
            return name.includes(q) || email.includes(q);
        });
    }, [candidates, query]);
    const commitSelection = useCallback((view) => {
        if (excluded.has(view.id))
            return;
        onChange({
            id: view.id,
            name: view.name || view.email || view.id,
            email: view.email,
            view,
        });
        setQuery("");
        setOpen(false);
    }, [excluded, onChange]);
    const handleKeyDown = useCallback((e) => {
        if (e.key === "ArrowDown") {
            e.preventDefault();
            setOpen(true);
            setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
        }
        else if (e.key === "ArrowUp") {
            e.preventDefault();
            setActiveIndex((i) => Math.max(i - 1, 0));
        }
        else if (e.key === "Enter") {
            e.preventDefault();
            const choice = filtered[activeIndex];
            if (choice && !excluded.has(choice.id))
                commitSelection(choice);
        }
        else if (e.key === "Escape") {
            setOpen(false);
        }
    }, [filtered, activeIndex, excluded, commitSelection]);
    // Selected state: show a chip with a clear affordance instead of the input.
    if (value) {
        return (_jsxs("div", { className: cn("space-y-1", className), children: [_jsx("span", { className: "block text-xs font-medium text-foreground", children: "Person" }), _jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-input bg-background px-2.5 py-1.5", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-[0.6rem] font-medium text-muted-foreground", "aria-hidden": "true", children: (value.name[0] ?? "?").toUpperCase() }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "truncate text-xs text-foreground", children: value.name }), _jsx(ProviderBadge, { principal: value.view })] }), value.email && value.email !== value.name && (_jsx("span", { className: "block truncate text-[0.6rem] text-muted-foreground", children: value.email }))] })] }), _jsx("button", { type: "button", onClick: () => onChange(null), disabled: disabled, "aria-label": "Clear selected person", className: cn("shrink-0 rounded p-0.5 text-muted-foreground", "hover:text-foreground hover:bg-accent-hover", "disabled:pointer-events-none disabled:opacity-50"), children: _jsx(ClearIcon, {}) })] })] }));
    }
    return (_jsxs("div", { className: cn("space-y-1", className), children: [_jsx("label", { htmlFor: `${listboxId}-input`, className: "block text-xs font-medium text-foreground", children: "Person" }), _jsxs("div", { className: "relative", children: [_jsx("input", { id: `${listboxId}-input`, ref: inputRef, type: "text", role: "combobox", "aria-expanded": open, "aria-controls": listboxId, "aria-autocomplete": "list", autoComplete: "off", value: query, onChange: (e) => {
                            setQuery(e.target.value);
                            setOpen(true);
                            setActiveIndex(0);
                        }, onFocus: () => setOpen(true), onBlur: () => {
                            // Delay so option mousedown can register before close.
                            window.setTimeout(() => setOpen(false), 120);
                        }, onKeyDown: handleKeyDown, placeholder: "Search by name or email", disabled: disabled || isLoading, autoFocus: true, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50") }), open && (_jsxs("ul", { id: listboxId, role: "listbox", "aria-label": "Organization members", className: cn("absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md border border-border bg-popover py-1 shadow-md"), children: [isLoading && (_jsx("li", { className: "px-2.5 py-2 text-xs text-muted-foreground", children: "Loading members\u2026" })), !isLoading && error && (_jsx("li", { className: "px-2.5 py-2 text-[0.65rem] text-destructive", role: "alert", children: getUserMessage(error) })), !isLoading && !error && filtered.length === 0 && (_jsx("li", { className: "px-2.5 py-2 text-xs text-muted-foreground", children: query.trim()
                                    ? "No members match your search."
                                    : "No members to share with." })), !isLoading &&
                                !error &&
                                filtered.map((c, index) => {
                                    const isExcluded = excluded.has(c.id);
                                    const isActive = index === activeIndex;
                                    const name = c.name || c.email || c.id;
                                    // Show the provider badge when it disambiguates: an external
                                    // identity source, or a shared email across candidates.
                                    const showBadge = !!providerLabel(c) &&
                                        (c.identityOrigin?.providerDisplayName !== "Stigmer" ||
                                            (!!c.email && duplicatedEmails.has(c.email.toLowerCase())));
                                    return (_jsxs("li", { role: "option", "aria-selected": isActive, "aria-disabled": isExcluded, onMouseEnter: () => setActiveIndex(index), onMouseDown: (e) => {
                                            // Prevent input blur before selection commits.
                                            e.preventDefault();
                                            if (!isExcluded)
                                                commitSelection(c);
                                        }, className: cn("flex items-center justify-between gap-2 px-2.5 py-1.5", isExcluded
                                            ? "cursor-not-allowed opacity-50"
                                            : "cursor-pointer", isActive && !isExcluded && "bg-accent-hover"), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-[0.6rem] font-medium text-muted-foreground", "aria-hidden": "true", children: (name[0] ?? "?").toUpperCase() }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "truncate text-xs text-foreground", children: name }), showBadge && _jsx(ProviderBadge, { principal: c })] }), c.email && c.email !== name && (_jsx("span", { className: "block truncate text-[0.6rem] text-muted-foreground", children: c.email }))] })] }), isExcluded && (_jsx("span", { className: "shrink-0 text-[0.6rem] text-muted-foreground", children: "Has access" }))] }, c.id));
                                })] }))] })] }));
}
function ClearIcon() {
    return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) }));
}
//# sourceMappingURL=PrincipalPicker.js.map