import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// (C) 2026 GoodData Corporation
import { useId, useState } from "react";
import { useIntl } from "react-intl";
import { commonDialogMessages, olpLabelMessages } from "../../locales.js";
import { bem } from "../@utils/bem.js";
import { UiButton } from "../UiButton/UiButton.js";
import { UiLabelChecklistRow } from "../UiLabelChecklistRow/UiLabelChecklistRow.js";
import { UiSubmenuHeader } from "../UiSubmenuHeader/UiSubmenuHeader.js";
const { b, e } = bem("gd-ui-kit-labels-checklist");
/**
 * Whether an item counts as selected: locked items always do, otherwise
 * membership in `selectedIds`. Exported so callers apply the same rule.
 *
 * @internal
 */
export const isLabelsChecklistItemChecked = (item, selectedIds) => item.locked === true || selectedIds.includes(item.id);
/**
 * Per-label checklist drill-in for the grantee "⋯" menu. Stages selection
 * internally, commits via `onApply`, and renders its own back-only header so it
 * slots into {@link UiMenu} as a `showComponentOnly` content item.
 *
 * @internal
 */
export function UiLabelsChecklist({ items, defaultSelectedIds, onApply, onBack, onClose, dataTestId, }) {
    const intl = useIntl();
    const groupId = useId();
    // Staged toggles only; locked ids are folded in by the predicate, not stored here.
    const [selected, setSelected] = useState(() => [...defaultSelectedIds]);
    const toggle = (id, next) => {
        setSelected((prev) => next ? (prev.includes(id) ? prev : [...prev, id]) : prev.filter((x) => x !== id));
    };
    const handleApply = () => {
        onApply(items.filter((item) => isLabelsChecklistItemChecked(item, selected)).map((item) => item.id));
        onClose();
    };
    // Dirty when any row's checked-state differs from its initial. Locked rows are
    // checked on both sides, so they never count as a change.
    const isDirty = items.some((item) => isLabelsChecklistItemChecked(item, defaultSelectedIds) !==
        isLabelsChecklistItemChecked(item, selected));
    const handleKeyDown = (event) => {
        // Enter commits — scoped to the rows so the footer buttons keep native Enter.
        if (event.key === "Enter" && isDirty) {
            event.preventDefault();
            handleApply();
        }
    };
    const suffixFor = (kind) => {
        if (!kind)
            return undefined;
        return intl.formatMessage(kind === "primary" ? olpLabelMessages.suffixPrimary : olpLabelMessages.suffixDefault);
    };
    return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [
            _jsx(UiSubmenuHeader, { title: intl.formatMessage(olpLabelMessages.popoverTitle), backAriaLabel: intl.formatMessage(olpLabelMessages.backAriaLabel), height: "medium", onBack: onBack }), _jsx("div", { id: groupId, className: e("items"), role: "group", "aria-label": intl.formatMessage(olpLabelMessages.popoverTitle), onKeyDown: handleKeyDown, children: items.map((item) => (_jsx(UiLabelChecklistRow, { label: item.label, kind: item.kind, suffix: suffixFor(item.kind), checked: isLabelsChecklistItemChecked(item, selected), disabled: item.locked, onChange: (next) => toggle(item.id, next) }, item.id))) }), _jsxs("div", { className: e("actions"), children: [
                    _jsx(UiButton, { variant: "secondary", size: "small", label: intl.formatMessage(commonDialogMessages.cancel), onClick: onClose }), _jsx(UiButton, { variant: "primary", size: "small", label: intl.formatMessage(commonDialogMessages.apply), onClick: handleApply, isDisabled: !isDirty })
                ] })
        ] }));
}
