import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import * as React from 'react';
import { unstable_debounce as debounce, unstable_ownerDocument as ownerDocument, unstable_useEnhancedEffect as useEnhancedEffect, unstable_ownerWindow as ownerWindow } from '@mui/utils';
import { useGridApiEventHandler, useGridApiOptionHandler } from '../../utils/useGridApiEventHandler';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { useGridLogger } from '../../utils/useGridLogger';
import { gridColumnsTotalWidthSelector } from '../columns';
import { gridDensityFactorSelector } from '../density';
import { useGridSelector } from '../../utils';
import { getVisibleRows } from '../../utils/useGridVisibleRows';
import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector';
import { calculatePinnedRowsHeight } from '../rows/gridRowsUtils';
import { getTotalHeaderHeight } from '../columns/gridColumnsUtils';
var isTestEnvironment = process.env.NODE_ENV === 'test';
var hasScroll = function hasScroll(_ref) {
  var content = _ref.content,
    container = _ref.container,
    scrollBarSize = _ref.scrollBarSize;
  var hasScrollXIfNoYScrollBar = content.width > container.width;
  var hasScrollYIfNoXScrollBar = content.height > container.height;
  var hasScrollX = false;
  var hasScrollY = false;
  if (hasScrollXIfNoYScrollBar || hasScrollYIfNoXScrollBar) {
    hasScrollX = hasScrollXIfNoYScrollBar;
    hasScrollY = content.height + (hasScrollX ? scrollBarSize : 0) > container.height;

    // We recalculate the scroll x to consider the size of the y scrollbar.
    if (hasScrollY) {
      hasScrollX = content.width + scrollBarSize > container.width;
    }
  }
  return {
    hasScrollX: hasScrollX,
    hasScrollY: hasScrollY
  };
};
export function useGridDimensions(apiRef, props) {
  var logger = useGridLogger(apiRef, 'useResizeContainer');
  var errorShown = React.useRef(false);
  var rootDimensionsRef = React.useRef(null);
  var fullDimensionsRef = React.useRef(null);
  var rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector);
  var densityFactor = useGridSelector(apiRef, gridDensityFactorSelector);
  var rowHeight = Math.floor(props.rowHeight * densityFactor);
  var totalHeaderHeight = getTotalHeaderHeight(apiRef, props.columnHeaderHeight);
  var updateGridDimensionsRef = React.useCallback(function () {
    var _apiRef$current$rootE;
    var rootElement = (_apiRef$current$rootE = apiRef.current.rootElementRef) == null ? void 0 : _apiRef$current$rootE.current;
    var columnsTotalWidth = gridColumnsTotalWidthSelector(apiRef);
    var pinnedRowsHeight = calculatePinnedRowsHeight(apiRef);
    if (!rootDimensionsRef.current) {
      return;
    }
    var scrollBarSize;
    if (props.scrollbarSize != null) {
      scrollBarSize = props.scrollbarSize;
    } else if (!columnsTotalWidth || !rootElement) {
      scrollBarSize = 0;
    } else {
      var doc = ownerDocument(rootElement);
      var scrollDiv = doc.createElement('div');
      scrollDiv.style.width = '99px';
      scrollDiv.style.height = '99px';
      scrollDiv.style.position = 'absolute';
      scrollDiv.style.overflow = 'scroll';
      scrollDiv.className = 'scrollDiv';
      rootElement.appendChild(scrollDiv);
      scrollBarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
      rootElement.removeChild(scrollDiv);
    }
    var viewportOuterSize;
    var hasScrollX;
    var hasScrollY;
    if (props.autoHeight) {
      hasScrollY = false;
      hasScrollX = Math.round(columnsTotalWidth) > rootDimensionsRef.current.width;
      viewportOuterSize = {
        width: rootDimensionsRef.current.width,
        height: rowsMeta.currentPageTotalHeight + (hasScrollX ? scrollBarSize : 0)
      };
    } else {
      viewportOuterSize = {
        width: rootDimensionsRef.current.width,
        height: rootDimensionsRef.current.height - totalHeaderHeight
      };
      var scrollInformation = hasScroll({
        content: {
          width: Math.round(columnsTotalWidth),
          height: rowsMeta.currentPageTotalHeight
        },
        container: {
          width: viewportOuterSize.width,
          height: viewportOuterSize.height - pinnedRowsHeight.top - pinnedRowsHeight.bottom
        },
        scrollBarSize: scrollBarSize
      });
      hasScrollY = scrollInformation.hasScrollY;
      hasScrollX = scrollInformation.hasScrollX;
    }
    var viewportInnerSize = {
      width: viewportOuterSize.width - (hasScrollY ? scrollBarSize : 0),
      height: viewportOuterSize.height - (hasScrollX ? scrollBarSize : 0)
    };
    var newFullDimensions = {
      viewportOuterSize: viewportOuterSize,
      viewportInnerSize: viewportInnerSize,
      hasScrollX: hasScrollX,
      hasScrollY: hasScrollY,
      scrollBarSize: scrollBarSize
    };
    var prevDimensions = fullDimensionsRef.current;
    fullDimensionsRef.current = newFullDimensions;
    if (newFullDimensions.viewportInnerSize.width !== (prevDimensions == null ? void 0 : prevDimensions.viewportInnerSize.width) || newFullDimensions.viewportInnerSize.height !== (prevDimensions == null ? void 0 : prevDimensions.viewportInnerSize.height)) {
      apiRef.current.publishEvent('viewportInnerSizeChange', newFullDimensions.viewportInnerSize);
    }
  }, [apiRef, props.scrollbarSize, props.autoHeight, rowsMeta.currentPageTotalHeight, totalHeaderHeight]);
  var _React$useState = React.useState(),
    _React$useState2 = _slicedToArray(_React$useState, 2),
    savedSize = _React$useState2[0],
    setSavedSize = _React$useState2[1];
  var debouncedSetSavedSize = React.useMemo(function () {
    return debounce(setSavedSize, 60);
  }, []);
  var previousSize = React.useRef();
  useEnhancedEffect(function () {
    if (savedSize) {
      updateGridDimensionsRef();
      apiRef.current.publishEvent('debouncedResize', rootDimensionsRef.current);
    }
  }, [apiRef, savedSize, updateGridDimensionsRef]);

  // This is the function called by apiRef.current.resize()
  var resize = React.useCallback(function () {
    apiRef.current.computeSizeAndPublishResizeEvent();
  }, [apiRef]);
  var getRootDimensions = React.useCallback(function () {
    return fullDimensionsRef.current;
  }, []);
  var getViewportPageSize = React.useCallback(function () {
    var dimensions = apiRef.current.getRootDimensions();
    if (!dimensions) {
      return 0;
    }
    var currentPage = getVisibleRows(apiRef, {
      pagination: props.pagination,
      paginationMode: props.paginationMode
    });

    // TODO: Use a combination of scrollTop, dimensions.viewportInnerSize.height and rowsMeta.possitions
    // to find out the maximum number of rows that can fit in the visible part of the grid
    if (props.getRowHeight) {
      var renderContext = apiRef.current.getRenderContext();
      var viewportPageSize = renderContext.lastRowIndex - renderContext.firstRowIndex;
      return Math.min(viewportPageSize - 1, currentPage.rows.length);
    }
    var maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / rowHeight);
    return Math.min(maximumPageSizeWithoutScrollBar, currentPage.rows.length);
  }, [apiRef, props.pagination, props.paginationMode, props.getRowHeight, rowHeight]);
  var computeSizeAndPublishResizeEvent = React.useCallback(function () {
    var _apiRef$current$mainE, _previousSize$current, _previousSize$current2;
    var mainEl = (_apiRef$current$mainE = apiRef.current.mainElementRef) == null ? void 0 : _apiRef$current$mainE.current;
    if (!mainEl) {
      return;
    }
    var height = mainEl.clientHeight || 0;
    var width = mainEl.clientWidth || 0;
    var win = ownerWindow(mainEl);
    var computedStyle = win.getComputedStyle(mainEl);
    var paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
    var paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
    var paddingTop = parseInt(computedStyle.paddingTop, 10) || 0;
    var paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0;
    var newHeight = height - paddingTop - paddingBottom;
    var newWidth = width - paddingLeft - paddingRight;
    var hasHeightChanged = newHeight !== ((_previousSize$current = previousSize.current) == null ? void 0 : _previousSize$current.height);
    var hasWidthChanged = newWidth !== ((_previousSize$current2 = previousSize.current) == null ? void 0 : _previousSize$current2.width);
    if (!previousSize.current || hasHeightChanged || hasWidthChanged) {
      var size = {
        width: newWidth,
        height: newHeight
      };
      apiRef.current.publishEvent('resize', size);
      previousSize.current = size;
    }
  }, [apiRef]);
  var dimensionsApi = {
    resize: resize,
    getRootDimensions: getRootDimensions
  };
  var dimensionsPrivateApi = {
    getViewportPageSize: getViewportPageSize,
    updateGridDimensionsRef: updateGridDimensionsRef,
    computeSizeAndPublishResizeEvent: computeSizeAndPublishResizeEvent
  };
  useGridApiMethod(apiRef, dimensionsApi, 'public');
  useGridApiMethod(apiRef, dimensionsPrivateApi, 'private');
  var isFirstSizing = React.useRef(true);
  var handleResize = React.useCallback(function (size) {
    rootDimensionsRef.current = size;

    // jsdom has no layout capabilities
    var isJSDOM = /jsdom/.test(window.navigator.userAgent);
    if (size.height === 0 && !errorShown.current && !props.autoHeight && !isJSDOM) {
      logger.error(['The parent DOM element of the data grid has an empty height.', 'Please make sure that this element has an intrinsic height.', 'The grid displays with a height of 0px.', '', 'More details: https://mui.com/r/x-data-grid-no-dimensions.'].join('\n'));
      errorShown.current = true;
    }
    if (size.width === 0 && !errorShown.current && !isJSDOM) {
      logger.error(['The parent DOM element of the data grid has an empty width.', 'Please make sure that this element has an intrinsic width.', 'The grid displays with a width of 0px.', '', 'More details: https://mui.com/r/x-data-grid-no-dimensions.'].join('\n'));
      errorShown.current = true;
    }
    if (isTestEnvironment) {
      // We don't need to debounce the resize for tests.
      setSavedSize(size);
      isFirstSizing.current = false;
      return;
    }
    if (isFirstSizing.current) {
      // We want to initialize the grid dimensions as soon as possible to avoid flickering
      setSavedSize(size);
      isFirstSizing.current = false;
      return;
    }
    debouncedSetSavedSize(size);
  }, [props.autoHeight, debouncedSetSavedSize, logger]);
  useEnhancedEffect(function () {
    return updateGridDimensionsRef();
  }, [updateGridDimensionsRef]);
  useGridApiOptionHandler(apiRef, 'sortedRowsSet', updateGridDimensionsRef);
  useGridApiOptionHandler(apiRef, 'paginationModelChange', updateGridDimensionsRef);
  useGridApiOptionHandler(apiRef, 'columnsChange', updateGridDimensionsRef);
  useGridApiEventHandler(apiRef, 'resize', handleResize);
  useGridApiOptionHandler(apiRef, 'debouncedResize', props.onResize);
}