/*
 * Copyright 2025 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import classnames from "classnames";
import React, { memo, useCallback, useMemo } from "react";
import { Combobox } from "../../../base-components/combobox/Combobox.js";
import { useFilterListBoundary } from "../FilterListBoundaryContext.js";
import { createRenderValueFilter } from "./comboboxFilter.js";
import { MultiSelectDropdownLayout } from "./MultiSelectDropdownLayout.js";
import { MultiSelectInlineLayout } from "./MultiSelectInlineLayout.js";
import { getOptionLabelText, OptionLabel } from "./OptionLabel.js";
import { SelectInputSkeleton } from "./SelectInputSkeleton.js";
import { useStableData } from "./useStableData.js";
import styles from "./MultiSelectInput.module.css.js";
import sharedStyles from "./shared.module.css.js";

/**
 * Layout for the value list:
 * - `"dropdown"` (default): chips inline + portaled Combobox popup. Use when
 *   the input drives its own surface (e.g. standalone in a row).
 * - `"inline"`: search input + always-visible value list rendered in flow.
 *   Use when wrapping the input in your own popover so the values are
 *   immediately visible without an extra inner trigger.
 */

function MultiSelectInputInner({
  values,
  isLoading,
  error,
  selectedValues,
  onChange,
  className,
  style,
  placeholder = "Select values...",
  showCounts = true,
  showFilteredOutValues = true,
  ariaLabel = "Search values",
  renderValue,
  layout = "dropdown"
}) {
  const collisionBoundary = useFilterListBoundary();
  const handleValueChange = useCallback(newValues => {
    onChange(newValues ?? []);
  }, [onChange]);
  const stableValues = useStableData(values, isLoading);
  const items = useMemo(() => stableValues.map(({
    value
  }) => value), [stableValues]);
  const countByValue = useMemo(() => new Map(stableValues.map(({
    value,
    count
  }) => [value, count])), [stableValues]);
  const selectedSet = useMemo(() => new Set(selectedValues), [selectedValues]);
  const comboboxFilter = useMemo(() => renderValue ? createRenderValueFilter(renderValue) : undefined, [renderValue]);
  const renderItem = useCallback(value => {
    const count = countByValue.get(value) ?? 0;
    const isFilteredOut = showFilteredOutValues && count === 0 && !selectedSet.has(value);
    return /*#__PURE__*/React.createElement(Combobox.Item, {
      key: value,
      value: value,
      className: isFilteredOut ? styles.filteredOutItem : undefined
    }, /*#__PURE__*/React.createElement(Combobox.ItemIndicator, null), /*#__PURE__*/React.createElement("span", {
      className: styles.itemLabel
    }, /*#__PURE__*/React.createElement(OptionLabel, {
      value: value,
      renderValue: renderValue
    })), showCounts && /*#__PURE__*/React.createElement("span", {
      className: styles.itemCount
    }, "(", count.toLocaleString(), ")"));
  }, [countByValue, selectedSet, showCounts, showFilteredOutValues, renderValue]);
  const renderChips = useCallback(selectedItems => /*#__PURE__*/React.createElement(React.Fragment, null, selectedItems.map(value => {
    return /*#__PURE__*/React.createElement(Combobox.Chip, {
      key: value,
      "aria-label": getOptionLabelText(value)
    }, /*#__PURE__*/React.createElement(OptionLabel, {
      value: value,
      renderValue: renderValue
    }), /*#__PURE__*/React.createElement(Combobox.ChipRemove, null));
  }), /*#__PURE__*/React.createElement(Combobox.Input, {
    placeholder: selectedItems.length > 0 ? "" : placeholder,
    "aria-label": ariaLabel
  })), [placeholder, ariaLabel, renderValue]);
  const isNoData = !error && stableValues.length === 0;
  const isReloading = isLoading && stableValues.length > 0;
  return /*#__PURE__*/React.createElement("div", {
    className: classnames(styles.multiSelect, className),
    style: style,
    "data-loading": isReloading
  }, /*#__PURE__*/React.createElement("span", {
    className: sharedStyles.srOnly,
    role: "status"
  }, isLoading ? "Loading options" : ""), error && /*#__PURE__*/React.createElement("div", {
    className: sharedStyles.errorMessage
  }, "Error loading options: ", error.message), isNoData && isLoading && /*#__PURE__*/React.createElement(SelectInputSkeleton, null), isNoData && !isLoading && /*#__PURE__*/React.createElement("div", {
    className: sharedStyles.emptyMessage
  }, "No options available"), stableValues.length > 0 && /*#__PURE__*/React.createElement(Combobox.Root, {
    multiple: true,
    value: selectedValues,
    onValueChange: handleValueChange,
    items: items,
    filter: comboboxFilter
  }, layout === "inline" ? /*#__PURE__*/React.createElement(MultiSelectInlineLayout, {
    placeholder: placeholder,
    ariaLabel: ariaLabel,
    renderItem: renderItem
  }) : /*#__PURE__*/React.createElement(MultiSelectDropdownLayout, {
    renderChips: renderChips,
    renderItem: renderItem,
    collisionBoundary: collisionBoundary
  })));
}
export const MultiSelectInput = /*#__PURE__*/memo(MultiSelectInputInner);
//# sourceMappingURL=MultiSelectInput.js.map