import { isString, omit } from 'lodash';
import React, { ReactNode, useMemo } from 'react';
import { SilkeCheckbox } from '../silke-checkbox';
import { SilkeOverflowMenu } from '../silke-overflow-menu';
import styles from './silke-table.scss';
import { TableColumn, TableRowMenu } from './table-types';

type TableRowProps<T> = {
  item: T;
  index: number;
  columns: TableColumn<T>[];
  selected?: boolean;
  multiselect?: boolean;
  search?: RegExp;
  menu?: TableRowMenu<T>[];
  onSelect?: (value: T, select: boolean) => void;
  onHover?: () => void;
};

function hasSearchMatch(search: RegExp, values: ReactNode[]): boolean {
  for (const value of values) {
    if (isString(value) && search.test(value)) return true;
  }
  return false;
}

const stopPropagation = (e: React.MouseEvent) => e.stopPropagation();

export function TableRow<T>({
  item,
  index,
  columns,
  search,
  menu,
  multiselect,
  selected,
  onSelect,
  onHover,
}: TableRowProps<T>) {
  // Mapping and transforming the item into column values
  const values = useMemo(() => {
    return columns.map((column) => {
      const value = item[column.attr];
      if (column.transform) return column.transform(value, item, index);
      return value as unknown as React.ReactElement;
    });
  }, [item, columns]);

  // Checking if one of the values matches the search
  if (search && !hasSearchMatch(search, values)) return null;
  const filteredMenu = menu
    ? menu
        .filter((m) => m === 'divider' || !m.isVisible || m.isVisible(item))
        .map((m) => (typeof m === 'object' ? omit(m, 'isVisible') : m))
    : undefined;
  return (
    <tr
      className={!multiselect && onSelect ? styles.selectable : undefined}
      onClick={!multiselect && onSelect ? () => onSelect(item, true) : undefined}
      onMouseEnter={onHover}
    >
      {multiselect && (
        <td className={styles.check}>
          <SilkeCheckbox
            value={selected}
            onChange={(select) => onSelect && onSelect(item, select)}
          />
        </td>
      )}
      {values.map((value, i) => (
        <td key={i} align={columns[i].align}>
          {value}
        </td>
      ))}
      {filteredMenu && (
        <td className={styles.menu} onClick={stopPropagation}>
          {filteredMenu.length > 0 && (
            <SilkeOverflowMenu
              kind="ghost"
              size="base"
              items={filteredMenu.map((m) =>
                m === 'divider' ? m : { ...m, onClick: () => m.onClick(item) },
              )}
            />
          )}
        </td>
      )}
    </tr>
  );
}
