import { forwardRef, useCallback, useMemo } from 'react';
import type { FC } from 'react';
import clsx from 'clsx';

import { useCardGridColDef } from './column-types';
import { CardGridContainer, CardGridHeader, CardGridRow, CardGridRowGroup } from './components';
import type { CardGridRowProps } from './components/CardGridRow';
import { CardGridProps, CardGridColDef } from './types';

/**
 * A CardGrid structure consisting of a header and rows based on the Card component.
 */
export const CardGrid: FC<CardGridProps> = forwardRef(function CardGrid(props, ref) {
  const {
    cols = [],
    rows = [],
    hideColumnHeaders = false,
    getCardGridRowProps,
    onCellClick,
    classes,
    className,
    ...otherProps
  } = props;

  const getCardGridColDef = useCardGridColDef();
  const getExtendedColDef = useCallback(
    (col: CardGridColDef, index?: number) => {
      const colDef = getCardGridColDef(col);
      const colTypeClass = `colType--${colDef.type || 'default'}`;
      const colClasses = {
        firstColumn: !index || index === 0,
        [colTypeClass]: true
      };
      return {
        ...colDef,
        className: clsx(colClasses, colDef.className)
      };
    },
    [getCardGridColDef]
  );
  const extendedCols = useMemo(() => cols.map(getExtendedColDef), [cols, getExtendedColDef]);

  /**
   * ARIA roles hierarchy (read-only treegrid):
   *  [treegrid] -> [rowgroup] -> [[row] -> [columnheader]]
   *  [treegrid] -> [rowgroup] -> [[row] -> [gridcell]]
   * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/treegrid_role#read-only_treegrids
   */
  return (
    <CardGridContainer
      ref={ref}
      role="treegrid"
      aria-readonly="true"
      className={clsx(classes?.container, className)}
      {...otherProps}
    >
      {!hideColumnHeaders && (
        <CardGridRowGroup role="rowgroup" className={classes?.rowGroup}>
          <CardGridHeader cols={extendedCols} className={classes?.header} />
        </CardGridRowGroup>
      )}
      <CardGridRowGroup role="rowgroup" className={classes?.rowGroup}>
        {rows?.map((row, rowIndex) => {
          let cardGridRowProps: CardGridRowProps = {
            cols: extendedCols,
            row,
            rowIndex
          };
          if (getCardGridRowProps) {
            cardGridRowProps = getCardGridRowProps(cardGridRowProps);
          }
          return (
            <CardGridRow
              key={row.id}
              className={classes?.row}
              onCellClick={onCellClick}
              {...cardGridRowProps}
            />
          );
        })}
      </CardGridRowGroup>
    </CardGridContainer>
  );
});

export default CardGrid;
