import colors from 'client/UIKit/colors';
import { Box } from 'client/UIKit/grid';
import mq from 'client/UIKit/mq';
import { pick } from 'lodash';
import { toJS } from 'mobx';
import { useMemo } from 'react';
import styled from 'styled-components';

const TableStyles = styled(Box)`
  overflow-x: auto;
  table {
    width: 100%;
    ${mq.laptop`
        overflow-x: none;
    `}
    table-layout: fixed;
    text-align: left;
    border-radius: 2px 2px 0 0;
    border-collapse: separate;
    border-spacing: 0;

    tr {
      width: 100%;
      :last-child {
        td {
          border-bottom: 0;
        }
      }
      transition: background 1s cubic-bezier(0.075, 0.82, 0.165, 1);
      :hover {
        background: ${colors.WHITE[25]};
      }
    }

    th {
      color: rgba(0, 0, 0, 0.85);
      font-weight: 500;
      text-align: left;
      background: ${colors.WHITE[25]};
      transition: background 0.3s ease;
      padding: 16px;
    }

    th,
    td {
      position: relative;
      text-overflow: ellipsis;
      overflow: hidden;
      border-bottom: 1px solid ${colors.WHITE[50]};
    }

    td {
      padding: 10px 16px;
      > * {
        margin: 0;
      }
    }
  }
`;

const TablesGrid = styled(Box)`
  display: ${props => props.split && 'grid'};
  grid-template-columns: 1fr;
  ${mq.laptop`
    grid-gap: 10px;
    grid-template-columns: repeat(${props =>
      props?.split?.columnsNumber || '2'}, 1fr);
    `}
`;

function buildHead(features, columns) {
  return () => (
    <thead>
      <tr>
        {features?.numerize && <th>{features.numerize.columnTitle || '#'}</th>}
        {columns.map(column => (
          <th key={column.name}>{column.title}</th>
        ))}
      </tr>
    </thead>
  );
}

function buildBody(
  tableName,
  features,
  rows,
  columnsProps,
  withTableValue,
  partNumber,
  rowsNumber,
) {
  return () => (
    <tbody>
      {rows.map((row, rowIndex) => {
        const partRowIndex = rowIndex + partNumber * rowsNumber;
        return (
          <tr key={row.key || rowIndex}>
            {features?.numerize && <td>{partRowIndex + 1}</td>}
            {Object.keys(row).map(propName => {
              if (propName === 'key') return null;
              const CellComponent = columnsProps[propName].Component;
              const Cell = withTableValue(CellComponent)({
                tableName,
                rowIndex: partRowIndex,
                propName,
                ...columnsProps[propName].props,
              });
              return (
                <td key={propName}>
                  <Cell />
                </td>
              );
            })}
          </tr>
        );
      })}
    </tbody>
  );
}

const useColumnsProps = columns =>
  useMemo(
    () =>
      columns.reduce((acc, col) => {
        acc[col.name] = pick(col, ['Component', 'props']);
        return acc;
      }, {}),
    [columns],
  );

const useSplit = (split, rows) => {
  return useMemo(() => {
    if (!split || !rows?.length) {
      return {
        partsNumber: 1,
      };
    }
    const { rowsNumber } = split;
    return { partsNumber: Math.ceil(rows?.length / rowsNumber), rowsNumber };
  }, [rows?.length]);
};

const Table = ({
  name: tableName,
  rows,
  columns,
  params: { features },
  withTableValue,
}) => {
  const split = useSplit(features?.split, rows);
  const rowsNumber = features?.split?.rowsNumber || rows?.length;
  const columnsProps = useColumnsProps(columns);

  const Head = buildHead(features, columns);
  const tables = useMemo(() => {
    let tables = [];
    for (const partNumber of Array.from(Array(split.partsNumber).keys())) {
      const a = 0 + rowsNumber * partNumber;
      const b = rowsNumber + rowsNumber * partNumber;

      const rowsPart = toJS(rows).slice(a, b);

      const Body = buildBody(
        tableName,
        features,
        rowsPart,
        columnsProps,
        withTableValue,
        partNumber,
        rowsNumber,
      );
      tables.push(
        <TableStyles key={partNumber.toString()}>
          <table>
            <Head />
            <Body />
          </table>
        </TableStyles>,
      );
    }
    return tables;
  }, [rows.length]);

  return <TablesGrid split={features?.split}>{tables}</TablesGrid>;
};

export default Table;
