import { css } from '@emotion/css';
import React from 'react';
import { FixedSizeGrid } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';

import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';

import { SearchCard } from '../../components/SearchCard';
import { useSearchKeyboardNavigation } from '../../hooks/useSearchKeyboardSelection';
import { queryResultToViewItem } from '../../service/utils';
import { DashboardViewItem } from '../../types';

import { SearchResultsProps } from './SearchResultsTable';

export const SearchResultsGrid = ({
  response,
  width,
  height,
  selection,
  selectionToggle,
  onTagSelected,
  onClickItem,
  keyboardEvents,
}: SearchResultsProps) => {
  const styles = useStyles2(getStyles);

  // Hacked to reuse existing SearchCard (and old DashboardSectionItem)
  const itemProps = {
    editable: selection != null,
    onToggleChecked: (item: DashboardViewItem) => {
      if (selectionToggle) {
        selectionToggle(item.kind, item.uid);
      }
    },
    onTagSelected,
    onClick: onClickItem,
  };

  const itemCount = response.totalRows ?? response.view.length;
  const view = response.view;
  const numColumns = Math.ceil(width / 320);
  const cellWidth = width / numColumns;
  const cellHeight = (cellWidth - 64) * 0.75 + 56 + 8;
  const numRows = Math.ceil(itemCount / numColumns);
  const highlightIndex = useSearchKeyboardNavigation(keyboardEvents, numColumns, response);

  return (
    <InfiniteLoader isItemLoaded={response.isItemLoaded} itemCount={itemCount} loadMoreItems={response.loadMoreItems}>
      {({ onItemsRendered, ref }) => (
        <FixedSizeGrid
          ref={ref}
          onItemsRendered={(v) => {
            onItemsRendered({
              visibleStartIndex: v.visibleRowStartIndex * numColumns,
              visibleStopIndex: v.visibleRowStopIndex * numColumns,
              overscanStartIndex: v.overscanRowStartIndex * numColumns,
              overscanStopIndex: v.overscanColumnStopIndex * numColumns,
            });
          }}
          columnCount={numColumns}
          columnWidth={cellWidth}
          rowCount={numRows}
          rowHeight={cellHeight}
          className={styles.wrapper}
          innerElementType="ul"
          height={height}
          width={width - 2}
        >
          {({ columnIndex, rowIndex, style }) => {
            const index = rowIndex * numColumns + columnIndex;
            if (index >= view.length) {
              return null;
            }
            const item = view.get(index);
            const kind = item.kind ?? 'dashboard';

            const facade = queryResultToViewItem(item, view);

            if (kind === 'panel') {
              const type = item.panel_type;
              facade.icon = 'public/img/icons/unicons/graph-bar.svg';
              if (type) {
                const info = config.panels[type];
                if (info?.name) {
                  const v = info.info?.logos.small;
                  if (v && v.endsWith('.svg')) {
                    facade.icon = v;
                  }
                }
              }
            }

            let className = styles.virtualizedGridItemWrapper;
            if (rowIndex === highlightIndex.y && columnIndex === highlightIndex.x) {
              className += ' ' + styles.selectedItem;
            }

            // The wrapper div is needed as the inner SearchItem has margin-bottom spacing
            // And without this wrapper there is no room for that margin
            return item ? (
              <li style={style} className={className}>
                <SearchCard
                  key={item.uid}
                  {...itemProps}
                  item={facade}
                  isSelected={selection ? selection(facade.kind, facade.uid) : false}
                />
              </li>
            ) : null;
          }}
        </FixedSizeGrid>
      )}
    </InfiniteLoader>
  );
};

const getStyles = (theme: GrafanaTheme2) => ({
  virtualizedGridItemWrapper: css`
    padding: 4px;
  `,
  wrapper: css`
    display: flex;
    flex-direction: column;

    > ul {
      list-style: none;
    }
  `,
  selectedItem: css`
    box-shadow: inset 1px 1px 3px 3px ${theme.colors.primary.border};
  `,
});
