/**
 * Copyright IBM Corp. 2020, 2026
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { __toESM } from "../../../../../_virtual/_rolldown/runtime.js";
import { require_classnames } from "../../../../../node_modules/classnames/index.js";
import { pkg } from "../../../../../settings.js";
import { useIsomorphicEffect } from "../../../../../global/js/hooks/useIsomorphicEffect.js";
import { usePresence } from "../../../../../global/js/hooks/usePresence.js";
import { usePrefersReducedMotion } from "../../../../../global/js/hooks/usePrefersReducedMotion.js";
import { ActionSet } from "../../../../ActionSet/ActionSet.js";
import { BATCH, CLEAR_FILTERS, INSTANT, PANEL, SAVED_FILTERS } from "./constants.js";
import { FilterContext } from "./FilterProvider.js";
import useSubscribeToEventEmitter from "./hooks/useSubscribeToEventEmitter.js";
import useFilters from "./hooks/useFilters.js";
import useShouldDisableButtons from "./hooks/useShouldDisableButtons.js";
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import PropTypes from "prop-types";
import { Accordion, AccordionItem, Button, Layer, Search } from "@carbon/react";
import { Close } from "@carbon/react/icons";
import { rem } from "@carbon/layout";
//#region src/components/Datagrid/Datagrid/addons/Filtering/FilterPanel.jsx
/**
* Copyright IBM Corp. 2022, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
var import_classnames = /* @__PURE__ */ __toESM(require_classnames());
const componentClass = `${`${pkg.prefix}--datagrid`}-filter-panel`;
const defaults = {
	title: "Filter",
	closeIconDescription: "Close filter panel",
	primaryActionLabel: "Apply",
	secondaryActionLabel: "Cancel",
	searchLabelText: "Filter search",
	searchPlaceholder: "Find filters"
};
const emptyArray = [];
const FilterPanel = ({ title = defaults.title, closeIconDescription = defaults.closeIconDescription, updateMethod, filterSections, setAllFilters, onApply = () => {}, onCancel = () => {}, onPanelOpen = () => {}, onPanelClose = () => {}, showFilterSearch = false, filterPanelMinHeight = 600, primaryActionLabel = defaults.primaryActionLabel, secondaryActionLabel = defaults.secondaryActionLabel, searchLabelText = defaults.searchLabelText, searchPlaceholder = defaults.searchPlaceholder, reactTableFiltersState = emptyArray, autoHideFilters = false, isFetching = false }) => {
	/** State */
	const [showDividerLine, setShowDividerLine] = useState(false);
	/** Context */
	const { panelOpen, setPanelOpen, dispatch: localDispatch } = useContext(FilterContext);
	const { filtersState, prevFiltersObjectArrayRef, prevFiltersRef, cancel, reset, renderFilter, filtersObjectArray, lastAppliedFilters } = useFilters({
		updateMethod,
		filters: filterSections,
		setAllFilters,
		variation: PANEL,
		reactTableFiltersState,
		onCancel,
		panelOpen,
		autoHideFilters,
		isFetching
	});
	/** Refs */
	const filterPanelRef = useRef(void 0);
	const filterHeadingRef = useRef(void 0);
	const filterSearchRef = useRef(void 0);
	const actionSetRef = useRef(void 0);
	const innerContainerRef = useRef(void 0);
	/** State from hooks */
	const [shouldDisableButtons, setShouldDisableButtons] = useShouldDisableButtons({
		initialValue: true,
		filtersState,
		prevFiltersRef,
		open: panelOpen
	});
	const shouldReduceMotion = usePrefersReducedMotion();
	const { shouldRender } = usePresence(panelOpen, filterPanelRef, shouldReduceMotion ? "filter-panel-exit-reduced" : "filter-panel-exit-left");
	const [animationComplete, setAnimationComplete] = useState(false);
	/** Memos */
	const showActionSet = useMemo(() => updateMethod === BATCH, [updateMethod]);
	/** Methods */
	const closePanel = () => {
		cancel();
		setPanelOpen(false);
	};
	useEffect(() => {
		if (shouldReduceMotion) setAnimationComplete(true);
	}, [shouldReduceMotion]);
	const onAnimationStart = () => {
		setAnimationComplete(false);
	};
	const onAnimationEnd = () => {
		setAnimationComplete(!animationComplete);
	};
	const apply = () => {
		setAllFilters(filtersObjectArray);
		onApply({
			filtersState,
			filtersObjectArray,
			lastAppliedFilters
		});
		setShouldDisableButtons(true);
		prevFiltersRef.current = JSON.stringify(filtersState);
		prevFiltersObjectArrayRef.current = JSON.stringify(filtersObjectArray);
		lastAppliedFilters.current = JSON.stringify(filtersObjectArray);
		localDispatch({
			type: SAVED_FILTERS,
			payload: { savedFilters: filtersObjectArray }
		});
	};
	const renderActionSet = () => {
		return showActionSet && /* @__PURE__ */ React.createElement(ActionSet, {
			actions: [{
				key: 1,
				kind: "primary",
				label: primaryActionLabel,
				onClick: apply,
				disabled: shouldDisableButtons
			}, {
				key: 2,
				kind: "secondary",
				label: secondaryActionLabel,
				onClick: cancel,
				disabled: shouldDisableButtons
			}],
			className: (0, import_classnames.default)(`${componentClass}__action-set`, { [`${componentClass}__animationComplete`]: animationComplete }),
			ref: actionSetRef
		});
	};
	const onInnerContainerScroll = (event) => {
		if (event.target.scrollTop > 0) setShowDividerLine(true);
		else setShowDividerLine(false);
	};
	/** Effects */
	useEffect(function liftOpenStateToParent() {
		if (panelOpen) onPanelOpen(panelOpen);
		else onPanelClose(panelOpen);
	}, [
		panelOpen,
		onPanelClose,
		onPanelOpen
	]);
	useEffect(function setPanelMinimumHeight() {
		filterPanelRef.current?.style.setProperty("--filter-panel-min-height", rem(filterPanelMinHeight));
	}, [filterPanelMinHeight, shouldRender]);
	useSubscribeToEventEmitter(CLEAR_FILTERS, (tableId) => {
		reset(tableId);
	});
	const getScrollableContainerHeight = useCallback(() => {
		const filterHeadingHeight = filterHeadingRef.current?.getBoundingClientRect().height;
		const filterSearchHeight = filterSearchRef.current?.getBoundingClientRect().height;
		const actionSetHeight = actionSetRef.current?.getBoundingClientRect().height;
		return panelOpen ? `calc(100vh - ${filterHeadingHeight}px - ${showFilterSearch ? filterSearchHeight : 0}px - ${updateMethod === "batch" ? actionSetHeight : 0}px)` : 0;
	}, [
		filterHeadingRef,
		filterSearchRef,
		actionSetRef,
		panelOpen,
		showFilterSearch,
		updateMethod
	]);
	useIsomorphicEffect(() => {
		const height = getScrollableContainerHeight();
		if (innerContainerRef.current && innerContainerRef.current.style && height) innerContainerRef.current.style.height = height;
	}, [
		getScrollableContainerHeight,
		innerContainerRef,
		shouldRender
	]);
	return shouldRender ? /* @__PURE__ */ React.createElement("div", {
		ref: filterPanelRef,
		onAnimationEnd,
		onAnimationStart,
		className: (0, import_classnames.default)(componentClass, `${componentClass}__container`, `${componentClass}--left-placement`, {
			[`${componentClass}--open`]: panelOpen,
			[`${componentClass}--closing`]: !panelOpen,
			[`${componentClass}--reduced-motion`]: shouldReduceMotion,
			[`${componentClass}--batch`]: showActionSet,
			[`${componentClass}--instant`]: !showActionSet
		})
	}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("header", {
		ref: filterHeadingRef,
		className: (0, import_classnames.default)(`${componentClass}__heading`, { [`${componentClass}__heading--with-divider`]: showDividerLine })
	}, /* @__PURE__ */ React.createElement("div", { className: `${componentClass}__title` }, title), /* @__PURE__ */ React.createElement(Button, {
		hasIconOnly: true,
		renderIcon: (props) => /* @__PURE__ */ React.createElement(Close, {
			size: 16,
			...props
		}),
		iconDescription: closeIconDescription,
		kind: "ghost",
		tooltipPosition: "bottom",
		tooltipAlignment: "end",
		onClick: closePanel
	}), showFilterSearch && /* @__PURE__ */ React.createElement(
		"div",
		/* istanbul ignore next */
		{
			ref: filterSearchRef,
			className: `${componentClass}__search`
		},
		/* @__PURE__ */ React.createElement(Layer, null, /* @__PURE__ */ React.createElement(Search, {
			labelText: searchLabelText,
			placeholder: searchPlaceholder,
			size: "sm"
		}))
	)), /* @__PURE__ */ React.createElement("div", {
		className: `${componentClass}__inner-container`,
		ref: innerContainerRef,
		onScroll: onInnerContainerScroll
	}, filterSections.map(({ categoryTitle = null, filters = [], hasAccordion }, index) => {
		return /* @__PURE__ */ React.createElement("div", {
			key: index,
			className: `${componentClass}__category`
		}, categoryTitle && /* @__PURE__ */ React.createElement("div", { className: `${componentClass}__category-title` }, categoryTitle), hasAccordion ? /* @__PURE__ */ React.createElement(Accordion, null, filters.map(({ filterLabel, filter }) => {
			return /* @__PURE__ */ React.createElement(AccordionItem, {
				title: filterLabel,
				key: filterLabel
			}, renderFilter(filter));
		})) : filters.map(({ filter }) => renderFilter(filter)));
	})), renderActionSet())) : null;
};
FilterPanel.propTypes = {
	autoHideFilters: PropTypes.bool,
	closeIconDescription: PropTypes.string,
	filterPanelMinHeight: PropTypes.number,
	filterSections: PropTypes.array,
	isFetching: PropTypes.bool,
	onApply: PropTypes.func,
	onCancel: PropTypes.func,
	onPanelClose: PropTypes.func,
	onPanelOpen: PropTypes.func,
	open: PropTypes.bool,
	primaryActionLabel: PropTypes.string,
	/**
	* Filters from react table's state
	*/
	reactTableFiltersState: PropTypes.arrayOf(PropTypes.shape({
		id: PropTypes.string.isRequired,
		type: PropTypes.string.isRequired,
		value: PropTypes.any.isRequired
	})),
	searchLabelText: PropTypes.string,
	searchPlaceholder: PropTypes.string,
	secondaryActionLabel: PropTypes.string,
	setAllFilters: PropTypes.func,
	showFilterSearch: PropTypes.bool,
	title: PropTypes.string,
	updateMethod: PropTypes.oneOf([BATCH, INSTANT])
};
//#endregion
export { FilterPanel as default };
