/**
 * 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 { usePreviousValue } from "../../global/js/hooks/usePreviousValue.js";
import { prepareProps } from "../../global/js/utils/props-helper.js";
import { deepCloneObject } from "../../global/js/utils/deepCloneObject.js";
import { removeCellSelections } from "./utils/removeCellSelections.js";
import { useSpreadsheetMouseUp } from "./hooks/useSpreadsheetMouseUp.js";
import { createCellSelectionArea } from "./utils/createCellSelectionArea.js";
import { checkActiveHeaderCell } from "./utils/checkActiveHeaderCell.js";
import { checkSelectedHeaderCell } from "./utils/checkSelectedHeaderCell.js";
import { getSpreadsheetWidth } from "./utils/getSpreadsheetWidth.js";
import { handleBodyCellClick, handleBodyCellHover, handleRowHeaderClick } from "./utils/commonEventHandlers.js";
import React, { forwardRef, useCallback, useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { px } from "@carbon/layout";
import { FixedSizeList } from "react-window";
//#region src/components/DataSpreadsheet/DataSpreadsheetBody.tsx
/**
* Copyright IBM Corp. 2022, 2022
*
* 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 blockClass = `${pkg.prefix}--data-spreadsheet`;
const DataSpreadsheetBody = forwardRef(({ activeCellRef, columns, activeCellCoordinates, defaultColumn, defaultEmptyRowCount, getTableBodyProps, headerGroups, setCurrentColumns, id, onDataUpdate, renderRowHeader, renderRowHeaderDirection, hasCustomRowHeader, prepareRow, rows, selectionAreaData, setSelectionAreaData, setActiveCellCoordinates, selectedHeaderReorderActive, setSelectedHeaderReorderActive, selectionAreas, setContainerHasFocus, setSelectionAreas, scrollBarSize, totalColumnsWidth, clickAndHoldActive, setClickAndHoldActive, currentMatcher, setCurrentMatcher, onSelectionAreaChange, setActiveCellInsideSelectionArea, totalVisibleColumns, setHeaderCellHoldActive, setColumnOrder, visibleColumns }, ref) => {
	const [validStartingPoint, setValidStartingPoint] = useState(false);
	const contentScrollRef = useRef(void 0);
	const previousState = usePreviousValue({
		selectionAreaData,
		clickAndHoldActive,
		rowHeight: defaultColumn?.rowHeight
	}) || {};
	useEffect(() => {
		ref?.current.style.setProperty(`--${blockClass}--total-width`, px((totalColumnsWidth || 0) + (scrollBarSize || 0)));
	}, [
		ref,
		scrollBarSize,
		totalColumnsWidth
	]);
	useEffect(() => {
		if (selectionAreaData?.length) {
			let selectionChanged = false;
			if (previousState?.selectionAreaData?.length !== selectionAreaData?.length || selectionAreaData?.[0]?.cells.length !== previousState?.selectionAreaData?.[0]?.cells.length) selectionChanged = true;
			if (!clickAndHoldActive && previousState?.clickAndHoldActive || selectionChanged) onSelectionAreaChange?.(selectionAreaData);
		}
	}, [
		previousState?.selectionAreaData,
		selectionAreaData,
		onSelectionAreaChange,
		clickAndHoldActive,
		previousState?.clickAndHoldActive
	]);
	useEffect(() => {
		if (selectionAreas && selectionAreas.length) selectionAreas.map((area) => {
			if (area.areaCreated) {
				const rowStart = Math.min(area.point1.row, area.point2.row);
				const rowEnd = Math.max(area.point1.row, area.point2.row);
				const columnStart = Math.min(area.point1.column, area.point2.column);
				const columnEnd = Math.max(area.point1.column, area.point2.column);
				const selectionData = {
					rows: {
						start: rowStart,
						end: rowEnd
					},
					columns: {
						start: columnStart,
						end: columnEnd
					},
					cells: populateSelectionAreaCellData({
						rowStart,
						rowEnd,
						columnStart,
						columnEnd
					}),
					selectionId: area.matcher
				};
				setSelectionAreaData?.((prev) => {
					return [...deepCloneObject(prev).filter((item) => item.selectionId !== area.matcher), selectionData];
				});
			}
			if (!area.areaCreated && area.point1 && area.point2 && area.matcher) createCellSelectionArea({
				ref,
				area,
				blockClass,
				defaultColumn,
				selectionAreas,
				setSelectionAreas,
				setActiveCellInsideSelectionArea,
				visibleColumns
			});
		});
	}, [
		selectionAreas,
		setSelectionAreas,
		defaultColumn,
		onSelectionAreaChange,
		setSelectionAreaData,
		ref,
		activeCellCoordinates,
		setActiveCellInsideSelectionArea,
		visibleColumns,
		hasCustomRowHeader
	]);
	const populateSelectionAreaCellData = ({ rowStart, rowEnd, columnStart, columnEnd }) => {
		const cellContainer = [];
		for (let rowIndex = rowStart; rowIndex <= rowEnd; rowIndex++) for (let columnIndex = columnStart; columnIndex <= columnEnd; columnIndex++) cellContainer.push([
			rowIndex,
			columnIndex,
			`${blockClass}__cell--${rowIndex}--${columnIndex}`
		]);
		return cellContainer;
	};
	useSpreadsheetMouseUp({
		currentMatcher,
		setClickAndHoldActive,
		setSelectionAreas,
		setValidStartingPoint,
		selectedHeaderReorderActive,
		setSelectedHeaderReorderActive,
		validStartingPoint,
		ref,
		setHeaderCellHoldActive,
		setColumnOrder,
		visibleColumns,
		setActiveCellCoordinates,
		rows,
		activeCellCoordinates,
		defaultColumn,
		selectionAreas
	});
	useEffect(() => {
		let listContainer;
		let activeCellButton;
		if (spreadsheetBodyRef?.current) {
			listContainer = spreadsheetBodyRef?.current;
			activeCellButton = listContainer?.querySelector(`.${blockClass}__active-cell--highlight`);
		}
		if (activeCellButton && defaultColumn?.rowHeight !== previousState.rowHeight) {
			activeCellButton.style.height = `${defaultColumn?.rowHeight}px`;
			if (activeCellCoordinates) {
				const activeTargetElement = ref?.current.querySelector(`[data-row-index="${activeCellCoordinates.row}"][data-column-index="${activeCellCoordinates.column}"]`);
				const listContainer = ref?.current.querySelector(`.${blockClass}__list--container`);
				let newActiveCellTopPosition;
				if (activeTargetElement && listContainer) newActiveCellTopPosition = activeTargetElement?.getBoundingClientRect().top - listContainer.getBoundingClientRect().top;
				activeCellButton.style.top = px(newActiveCellTopPosition);
				removeCellSelections({
					matcher: void 0,
					spreadsheetRef: ref
				});
				selectionAreas?.map((area) => {
					if (!area.areaCreated && area.point1 && area.point2 && area.matcher) return createCellSelectionArea({
						ref,
						area,
						blockClass,
						defaultColumn,
						selectionAreas,
						setSelectionAreas,
						setActiveCellInsideSelectionArea,
						visibleColumns
					});
				});
			}
		}
	}, [
		defaultColumn,
		ref,
		activeCellCoordinates,
		previousState?.rowHeight,
		selectionAreas,
		setActiveCellInsideSelectionArea,
		setSelectionAreas,
		visibleColumns,
		hasCustomRowHeader
	]);
	const removeDuplicateSelections = useCallback(() => {
		const uniqueAttrArray = [], removedSelectionAreaMatcherArr = [];
		ref?.current.querySelectorAll(`.${blockClass}__selection-area--element`).forEach((selectorEl) => {
			const { top, left, height, width } = selectorEl.style;
			const uniqueAttrStr = `${top}${left}${height}${width}`;
			if (uniqueAttrArray.indexOf(uniqueAttrStr) == -1) uniqueAttrArray.push(uniqueAttrStr);
			else {
				selectorEl.remove();
				removedSelectionAreaMatcherArr.push(selectorEl.getAttribute("data-matcher-id"));
			}
		});
		if (removedSelectionAreaMatcherArr.length) {
			setSelectionAreas?.((prev) => {
				return deepCloneObject(prev).filter((item) => !removedSelectionAreaMatcherArr.includes(item.matcher));
			});
			setSelectionAreaData?.((prev) => {
				return deepCloneObject(prev).filter((item) => !removedSelectionAreaMatcherArr.includes(item.selectionId));
			});
		}
	}, [
		ref,
		setSelectionAreas,
		setSelectionAreaData
	]);
	useEffect(() => {
		removeDuplicateSelections();
	}, [selectionAreas, removeDuplicateSelections]);
	const handleBodyCellClickEvent = useCallback((cell, columnIndex) => {
		return (event) => {
			handleBodyCellClick(cell, columnIndex, event, currentMatcher, activeCellCoordinates, selectionAreas, setActiveCellCoordinates, setSelectionAreas, setContainerHasFocus, setClickAndHoldActive, setCurrentMatcher, ref, setSelectionAreaData, setActiveCellInsideSelectionArea, activeCellRef, setValidStartingPoint);
		};
	}, [
		currentMatcher,
		activeCellCoordinates,
		selectionAreas,
		setActiveCellCoordinates,
		setSelectionAreas,
		setContainerHasFocus,
		setClickAndHoldActive,
		setCurrentMatcher,
		ref,
		setSelectionAreaData,
		setActiveCellInsideSelectionArea,
		activeCellRef
	]);
	const handleBodyScroll = () => {
		const headerRowElement = ref.current.querySelector(`
        .${blockClass}__header--container .${blockClass}__tr`) || new HTMLDivElement();
		headerRowElement.scrollLeft = contentScrollRef?.current.scrollLeft;
	};
	useEffect(() => {
		contentScrollRef.current.addEventListener("scroll", () => handleBodyScroll());
		const contentScrollElementRef = contentScrollRef.current || new HTMLElement();
		return () => {
			contentScrollElementRef.removeEventListener("scroll", handleBodyScroll);
		};
	});
	const handleBodyCellHoverEvent = useCallback((cell, columnIndex) => {
		return () => {
			handleBodyCellHover(cell, columnIndex, clickAndHoldActive, currentMatcher, setSelectionAreas);
		};
	}, [
		clickAndHoldActive,
		currentMatcher,
		setSelectionAreas
	]);
	const handleRowHeaderClickEvent = useCallback((index) => {
		return (event) => {
			handleRowHeaderClick(index, event, columns, ref, setSelectionAreas, setCurrentMatcher, setActiveCellCoordinates, activeCellCoordinates, rows, setSelectionAreaData);
		};
	}, [
		columns,
		ref,
		setSelectionAreas,
		setCurrentMatcher,
		setActiveCellCoordinates,
		activeCellCoordinates,
		rows,
		setSelectionAreaData
	]);
	useEffect(() => {
		if (!rows?.length) {
			const buildEmptyRows = () => {
				const emptyRowData = [];
				[...Array(defaultEmptyRowCount)].map(() => {
					const emptyCell = {};
					headerGroups?.[0]?.headers.map((header) => {
						emptyCell[header.id] = null;
					});
					emptyRowData.push(emptyCell);
				});
				onDataUpdate?.(emptyRowData);
			};
			buildEmptyRows();
		}
		if (headerGroups?.[0] && typeof setCurrentColumns === "function") {
			const headers = headerGroups[0].headers;
			setCurrentColumns(headers);
		}
	}, [
		rows,
		headerGroups,
		defaultEmptyRowCount,
		onDataUpdate,
		setCurrentColumns
	]);
	const RenderEmptyRows = () => {
		return /* @__PURE__ */ React.createElement("div", null);
	};
	const RenderRow = useCallback(({ index, style }) => {
		const row = rows?.[index];
		if (rows && rows.length) {
			prepareRow?.(row);
			const rowProps = prepareProps(row.getRowProps({ style }), "key");
			return /* @__PURE__ */ React.createElement("div", {
				key: { ...row.getRowProps().key },
				...rowProps,
				className: (0, import_classnames.default)(`${blockClass}__tr`),
				"data-row-index": index,
				"aria-rowindex": index + 1,
				"aria-owns": `${blockClass}__cell-editor-text-area`
			}, /* @__PURE__ */ React.createElement("div", {
				role: "rowheader",
				className: `${blockClass}__td-th--cell-container`
			}, /* @__PURE__ */ React.createElement("button", {
				id: `${blockClass}__cell--${index}--header`,
				tabIndex: -1,
				"data-row-index": index,
				"data-column-index": "header",
				type: "button",
				onClick: handleRowHeaderClickEvent(index),
				className: (0, import_classnames.default)(`${blockClass}__td`, `${blockClass}__td-th`, `${blockClass}--interactive-cell-element`, {
					[`${blockClass}__td_custom`]: hasCustomRowHeader ? true : false,
					[`${blockClass}__td-th--active-header`]: !hasCustomRowHeader && (activeCellCoordinates?.row === index || checkActiveHeaderCell(index, selectionAreas, "row")),
					[`${blockClass}__td-th--selected-header`]: !hasCustomRowHeader && checkSelectedHeaderCell(index, selectionAreas, "row", columns)
				}),
				style: {
					width: defaultColumn?.rowHeaderWidth,
					flexDirection: hasCustomRowHeader ? renderRowHeaderDirection === "Left" ? "row-reverse" : row : void 0
				}
			}, index + 1, hasCustomRowHeader && typeof renderRowHeader === "function" && renderRowHeader(index))), row.cells.map((cell, index) => {
				const cellProps = prepareProps(cell.getCellProps(), "key");
				return /* @__PURE__ */ React.createElement("div", {
					key: `cell_${index}`,
					"aria-colindex": index + 1,
					...cellProps,
					role: "gridcell",
					style: {
						...cell.getCellProps().style,
						display: "grid",
						minWidth: cell?.column?.width || defaultColumn?.width
					}
				}, /* @__PURE__ */ React.createElement("button", {
					id: `${blockClass}__cell--${cell.row.index}--${index}`,
					tabIndex: -1,
					"data-row-index": cell.row.index,
					"data-column-index": index,
					className: (0, import_classnames.default)(`${blockClass}__td`, `${blockClass}__body--td`, `${blockClass}--interactive-cell-element`),
					onMouseDown: handleBodyCellClickEvent(cell, index),
					onMouseOver: handleBodyCellHoverEvent(cell, index),
					onFocus: () => {},
					type: "button"
				}, cell.render("Cell")));
			}));
		}
	}, [
		prepareRow,
		renderRowHeader,
		rows,
		hasCustomRowHeader,
		activeCellCoordinates?.row,
		selectionAreas,
		handleRowHeaderClickEvent,
		handleBodyCellClickEvent,
		handleBodyCellHoverEvent,
		columns,
		defaultColumn,
		renderRowHeaderDirection
	]);
	const spreadsheetBodyRef = useRef(void 0);
	return /* @__PURE__ */ React.createElement("div", {
		ref: spreadsheetBodyRef,
		className: (0, import_classnames.default)(`${blockClass}__body--container`),
		...getTableBodyProps?.()
	}, /* @__PURE__ */ React.createElement(FixedSizeList, {
		className: (0, import_classnames.default)(`${blockClass}__list--container`, `${blockClass}__list--container--${id}`),
		height: 400,
		itemCount: rows?.length || defaultEmptyRowCount,
		itemSize: defaultColumn?.rowHeight,
		width: getSpreadsheetWidth({
			headerGroup: void 0,
			type: void 0,
			scrollBarSizeValue: scrollBarSize,
			totalVisibleColumns,
			defaultColumn,
			totalColumnsWidth,
			visibleColumns
		}),
		outerRef: contentScrollRef
	}, rows?.length ? RenderRow : RenderEmptyRows));
});
DataSpreadsheetBody.propTypes = {
	/**
	* Object containing the active cell coordinates
	*/
	/**@ts-ignore */
	activeCellCoordinates: PropTypes.shape({
		row: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
		column: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
	}),
	/**
	*This is the ref of the button input, which is the active cell element
	*/
	/**@ts-ignore */
	activeCellRef: PropTypes.object,
	/**
	* Is the user clicking and holding in the data spreadsheet body
	*/
	clickAndHoldActive: PropTypes.bool,
	/**
	* All of the spreadsheet columns
	*/
	columns: PropTypes.array,
	/**
	* This represents the id of the current cell selection area
	*/
	currentMatcher: PropTypes.string,
	/**
	* Default spreadsheet sizing values
	*/
	/**@ts-ignore */
	defaultColumn: PropTypes.shape({
		rowHeight: PropTypes.number,
		rowHeaderWidth: PropTypes.number,
		width: PropTypes.number
	}),
	/**
	* Sets the number of empty rows to be created when there is no data provided
	*/
	defaultEmptyRowCount: PropTypes.number,
	/**
	* Function to set table body prop values
	*/
	/**@ts-ignore */
	getTableBodyProps: PropTypes.func,
	/**
	* Check if spreadsheet is using custom row header component attached
	*/
	hasCustomRowHeader: PropTypes.bool,
	/**
	* Headers provided from useTable hook
	*/
	headerGroups: PropTypes.arrayOf(PropTypes.object),
	/**
	* The spreadsheet id
	*/
	id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
	/**
	* The event handler that is called when the active cell changes
	*/
	onActiveCellChange: PropTypes.func,
	/**
	* The event handler that is called to set the rows for the empty spreadsheet
	*/
	onDataUpdate: PropTypes.func,
	/**
	* The event handler that is called when the selection areas change
	*/
	onSelectionAreaChange: PropTypes.func,
	/**
	* Prepare row function from react-table
	*/
	prepareRow: PropTypes.func,
	/**
	* Component next to numbering rows
	*/
	renderRowHeader: PropTypes.func,
	/**
	* Component next to numbering rows
	*/
	renderRowHeaderDirection: PropTypes.string,
	/**
	* All of the spreadsheet row data
	*/
	rows: PropTypes.arrayOf(PropTypes.object),
	/**
	* The scrollbar width
	*/
	scrollBarSize: PropTypes.number,
	/**
	* Header reordering is active
	*/
	selectedHeaderReorderActive: PropTypes.bool,
	/**
	* Array of selection area data
	*/
	selectionAreaData: PropTypes.array,
	/**
	* Array of selection areas
	*/
	selectionAreas: PropTypes.array,
	/**
	* Setter fn for activeCellCoordinates state value
	*/
	setActiveCellCoordinates: PropTypes.func,
	/**
	* Setter fn for active cell inside of selection area
	*/
	setActiveCellInsideSelectionArea: PropTypes.func,
	/**
	* Setter fn for clickAndHold state value
	*/
	setClickAndHoldActive: PropTypes.func,
	/**
	* Setter fn for column ordering, provided from react-table
	*/
	setColumnOrder: PropTypes.func,
	/**
	* Setter fn for containerHasFocus state value
	*/
	setContainerHasFocus: PropTypes.func,
	/**
	* Set current columns after drag drop
	*/
	setCurrentColumns: PropTypes.func,
	/**
	* Setter fn for currentMatcher state value
	*/
	setCurrentMatcher: PropTypes.func,
	/**
	* Setter fn for header cell hold active value
	*/
	setHeaderCellHoldActive: PropTypes.func,
	/**
	* Set header reordering active or not
	*/
	setSelectedHeaderReorderActive: PropTypes.func,
	/**
	* Setter fn for selectionAreaData state value
	*/
	setSelectionAreaData: PropTypes.func,
	/**
	* Setter fn for selectionAreas state value
	*/
	setSelectionAreas: PropTypes.func,
	/**
	* The total columns width
	*/
	totalColumnsWidth: PropTypes.number,
	/**
	* The total number of columns to be initially visible, additional columns will be rendered and
	* visible via horizontal scrollbar
	*/
	totalVisibleColumns: PropTypes.number,
	/**
	* Prop from react-table used to reorder columns
	*/
	/**@ts-ignore */
	visibleColumns: PropTypes.array
};
//#endregion
export { DataSpreadsheetBody };
