import { jsxs, jsx } from 'react/jsx-runtime';
import { css, cx } from '@emotion/css';
import { useState, useMemo, useCallback, useEffect } from 'react';
import { VariableSizeList } from 'react-window';
import { Subscription, debounceTime } from 'rxjs';
import { FieldType, hasTimeField, DataHoverEvent, DataHoverClearEvent } from '@grafana/data';
import { TableCellHeight, TableCellDisplayMode } from '@grafana/schema';
import { useTheme2 } from '../../themes/ThemeContext.js';
import 'micro-memoize';
import '@emotion/react';
import 'tinycolor2';
import '../../utils/skeleton.js';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar.js';
import '../PanelChrome/index.js';
import { ExpandedRow, getExpandedRowHeight } from './ExpandedRow.js';
import { TableCell } from './TableCell.js';
import { calculateAroundPointThreshold, isPointTimeValAroundTableTimeVal, guessTextBoundingBox, getCellColors } from './utils.js';
import { usePanelContext } from '../PanelChrome/PanelContext.js';

const RowsList = (props) => {
  const {
    data,
    rows,
    headerHeight,
    footerPaginationEnabled,
    rowHeight,
    itemCount,
    pageIndex,
    tableState,
    prepareRow,
    onCellFilterAdded,
    width,
    cellHeight = TableCellHeight.Sm,
    timeRange,
    tableStyles,
    nestedDataField,
    listHeight,
    listRef,
    enableSharedCrosshair = false,
    initialRowIndex = void 0,
    headerGroups,
    longestField,
    textWrapField
  } = props;
  const [rowHighlightIndex, setRowHighlightIndex] = useState(initialRowIndex);
  if (initialRowIndex === void 0 && rowHighlightIndex !== void 0) {
    setRowHighlightIndex(void 0);
  }
  const theme = useTheme2();
  const panelContext = usePanelContext();
  let osContext = null;
  if (window.OffscreenCanvas !== void 0) {
    osContext = new OffscreenCanvas(256, 1024).getContext("2d");
  }
  if (osContext !== void 0 && osContext !== null) {
    osContext.font = `${theme.typography.fontSize}px ${theme.typography.body.fontFamily}`;
  }
  const threshold = useMemo(() => {
    const timeField = data.fields.find((f) => f.type === FieldType.time);
    if (!timeField) {
      return 0;
    }
    return calculateAroundPointThreshold(timeField);
  }, [data]);
  const onRowHover = useCallback(
    (idx, frame) => {
      if (!panelContext || !enableSharedCrosshair || !hasTimeField(frame)) {
        return;
      }
      const timeField = frame.fields.find((f) => f.type === FieldType.time);
      panelContext.eventBus.publish(
        new DataHoverEvent({
          point: {
            time: timeField.values[idx]
          }
        })
      );
    },
    [enableSharedCrosshair, panelContext]
  );
  const onRowLeave = useCallback(() => {
    if (!panelContext || !enableSharedCrosshair) {
      return;
    }
    panelContext.eventBus.publish(new DataHoverClearEvent());
  }, [enableSharedCrosshair, panelContext]);
  const onDataHoverEvent = useCallback(
    (evt) => {
      var _a;
      if (((_a = evt.payload.point) == null ? void 0 : _a.time) && evt.payload.rowIndex !== void 0) {
        const timeField = data.fields.find((f) => f.type === FieldType.time);
        const time = timeField.values[evt.payload.rowIndex];
        const pointTime = evt.payload.point.time;
        if (isPointTimeValAroundTableTimeVal(pointTime, time, threshold)) {
          setRowHighlightIndex(evt.payload.rowIndex);
          return;
        }
        const matchedRowIndex = timeField.values.findIndex(
          (t) => isPointTimeValAroundTableTimeVal(pointTime, t, threshold)
        );
        if (matchedRowIndex !== -1) {
          setRowHighlightIndex(matchedRowIndex);
          return;
        }
        setRowHighlightIndex(void 0);
      }
    },
    [data.fields, threshold]
  );
  useEffect(() => {
    if (!panelContext || !enableSharedCrosshair || !hasTimeField(data) || footerPaginationEnabled) {
      return;
    }
    const subs = new Subscription();
    subs.add(
      panelContext.eventBus.getStream(DataHoverEvent).pipe(debounceTime(250)).subscribe({
        next: (evt) => {
          if (panelContext.eventBus === evt.origin) {
            return;
          }
          onDataHoverEvent(evt);
        }
      })
    );
    subs.add(
      panelContext.eventBus.getStream(DataHoverClearEvent).pipe(debounceTime(250)).subscribe({
        next: (evt) => {
          if (panelContext.eventBus === evt.origin) {
            return;
          }
          setRowHighlightIndex(void 0);
        }
      })
    );
    return () => {
      subs.unsubscribe();
    };
  }, [data, enableSharedCrosshair, footerPaginationEnabled, onDataHoverEvent, panelContext]);
  let scrollTop = void 0;
  if (rowHighlightIndex !== void 0) {
    const firstMatchedRowIndex = rows.findIndex((row) => row.index === rowHighlightIndex);
    if (firstMatchedRowIndex !== -1) {
      scrollTop = headerHeight + (firstMatchedRowIndex - 1) * rowHeight;
    }
  }
  const rowIndexForPagination = useCallback(
    (index) => {
      return tableState.pageIndex * tableState.pageSize + index;
    },
    [tableState.pageIndex, tableState.pageSize]
  );
  let rowBg = void 0;
  let textWrapFinal;
  for (const field of data.fields) {
    const fieldOptions = field.config.custom;
    const cellOptionsExist = fieldOptions !== void 0 && fieldOptions.cellOptions !== void 0;
    if (cellOptionsExist && fieldOptions.cellOptions.type === TableCellDisplayMode.ColorBackground && fieldOptions.cellOptions.applyToRow) {
      rowBg = (rowIndex) => {
        const display = field.display(field.values.get(rowIndex));
        const colors = getCellColors(tableStyles, fieldOptions.cellOptions, display);
        return colors;
      };
    }
    if (textWrapField !== void 0) {
      textWrapFinal = textWrapField;
    } else if (longestField !== void 0) {
      textWrapFinal = longestField;
    }
  }
  const RenderRow = useCallback(
    ({ index, style, rowHighlightIndex: rowHighlightIndex2 }) => {
      const indexForPagination = rowIndexForPagination(index);
      const row = rows[indexForPagination];
      let additionalProps = {};
      prepareRow(row);
      const expandedRowStyle = tableState.expanded[row.id] ? css({ "&:hover": { background: "inherit" } }) : {};
      const rowExpanded = nestedDataField && tableState.expanded[row.id];
      if (rowHighlightIndex2 !== void 0 && row.index === rowHighlightIndex2) {
        style = { ...style, backgroundColor: theme.components.table.rowSelected };
        additionalProps = {
          "aria-selected": "true"
        };
      }
      if (rowBg) {
        const { bgColor, textColor } = rowBg(row.index);
        style.background = bgColor;
        style.color = textColor;
      }
      if (textWrapFinal) {
        const visibleFields = data.fields.filter((field) => {
          var _a;
          return !Boolean((_a = field.config.custom) == null ? void 0 : _a.hidden);
        });
        const seriesIndex = visibleFields.findIndex((field) => field.name === textWrapFinal.name);
        const pxLineHeight = theme.typography.body.lineHeight * theme.typography.fontSize;
        const bbox = guessTextBoundingBox(
          textWrapFinal.values[row.index],
          headerGroups[0].headers[seriesIndex],
          osContext,
          pxLineHeight,
          tableStyles.rowHeight,
          tableStyles.cellPadding
        );
        style.height = bbox.height;
      }
      const { key, ...rowProps } = row.getRowProps({ style, ...additionalProps });
      return /* @__PURE__ */ jsxs(
        "div",
        {
          ...rowProps,
          className: cx(tableStyles.row, expandedRowStyle),
          onMouseEnter: () => onRowHover(index, data),
          onMouseLeave: onRowLeave,
          children: [
            rowExpanded && /* @__PURE__ */ jsx(
              ExpandedRow,
              {
                nestedData: nestedDataField,
                tableStyles,
                rowIndex: row.index,
                width,
                cellHeight
              }
            ),
            row.cells.map((cell, index2) => /* @__PURE__ */ jsx(
              TableCell,
              {
                tableStyles,
                cell,
                onCellFilterAdded,
                columnIndex: index2,
                columnCount: row.cells.length,
                timeRange,
                frame: data,
                rowStyled: rowBg !== void 0,
                rowExpanded,
                textWrapped: textWrapFinal !== void 0,
                height: Number(style.height)
              },
              index2
            ))
          ]
        },
        key
      );
    },
    [
      cellHeight,
      data,
      nestedDataField,
      onCellFilterAdded,
      onRowHover,
      onRowLeave,
      prepareRow,
      rowIndexForPagination,
      rows,
      tableState.expanded,
      tableStyles,
      textWrapFinal,
      theme.components.table.rowSelected,
      theme.typography.fontSize,
      theme.typography.body.lineHeight,
      timeRange,
      width,
      rowBg,
      headerGroups,
      osContext
    ]
  );
  const getItemSize = (index) => {
    const indexForPagination = rowIndexForPagination(index);
    const row = rows[indexForPagination];
    if (tableState.expanded[row.id] && nestedDataField) {
      return getExpandedRowHeight(nestedDataField, row.index, tableStyles);
    }
    if (textWrapFinal) {
      const visibleFields = data.fields.filter((field) => {
        var _a;
        return !Boolean((_a = field.config.custom) == null ? void 0 : _a.hidden);
      });
      const seriesIndex = visibleFields.findIndex((field) => field.name === textWrapFinal.name);
      const pxLineHeight = theme.typography.fontSize * theme.typography.body.lineHeight;
      return guessTextBoundingBox(
        textWrapFinal.values[row.index],
        headerGroups[0].headers[seriesIndex],
        osContext,
        pxLineHeight,
        tableStyles.rowHeight,
        tableStyles.cellPadding
      ).height;
    }
    return tableStyles.rowHeight;
  };
  const handleScroll = (event) => {
    const { scrollTop: scrollTop2 } = event.currentTarget;
    if (listRef.current !== null) {
      listRef.current.scrollTo(scrollTop2);
    }
  };
  const expandedKey = Object.keys(tableState.expanded).join("|");
  useEffect(() => {
    if (listRef.current) {
      listRef.current.resetAfterIndex(0);
    }
  }, [rows, listRef]);
  return /* @__PURE__ */ jsx(CustomScrollbar, { onScroll: handleScroll, hideHorizontalTrack: true, scrollTop, children: /* @__PURE__ */ jsx(
    VariableSizeList,
    {
      height: listHeight,
      itemCount,
      itemSize: getItemSize,
      width: "100%",
      ref: listRef,
      style: { overflow: void 0 },
      children: ({ index, style }) => RenderRow({ index, style, rowHighlightIndex })
    },
    `${rowHeight}${pageIndex}${expandedKey}`
  ) });
};

export { RowsList };
//# sourceMappingURL=RowsList.js.map
