import React, { useState, useEffect, useRef } from 'react';

// Redux part
import { useSelector } from 'react-redux';
import { StoreState } from 'store/rootReducer';

// Import actions here

import classNames from 'classnames/bind';
import TextItem from 'components/items/TextItem';

import Table from 'react-virtualized/dist/commonjs/Table';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import Column from 'react-virtualized/dist/commonjs/Table/Column';
import SortDirection from 'react-virtualized/dist/commonjs/Table/SortDirection';

import orderBy from 'lodash/orderBy';
import get from 'lodash/get';

import { CgSortAz, CgSortZa } from 'react-icons/cg';

import DateItem from 'components/items/DateItem/DateItem';
import styleIdentifiers from './CustomVirtualTable.module.scss';

import '!style-loader!css-loader!react-virtualized/styles.css';

const styles = classNames.bind(styleIdentifiers);

export interface StateProps {
  headers: object[];
  onRowClick?: Function;
  onRowDoubleClick?: Function;
  onScroll?: Function;
  items: object[];

  rowHeight?: number;
  headerHeight?: number;
  className?: string;
  tableClassName?: string;
  headerClassName?: string;
  cellClassName?: string;
  headerRowClassName?: string;
  rowClassName?: string;

  autoHeight?: boolean;

  headerRendererFunction?: Function;
  cellRenderedFunction?: Function;

  disableHeight?: boolean;
  disableWidth?: boolean;
}

export interface DispatchProps {}

export interface OwnProps {}

export type CustomVirtualTableProps = StateProps & DispatchProps & OwnProps;

const CustomVirtualTable = (props: CustomVirtualTableProps) => {
  const {
    headers,
    tableClassName,
    headerClassName,
    cellClassName,
    headerRowClassName,
    rowClassName,
    forcedWidth,
    rowHeight,
    headerHeight,
    data,
    headerRendererFunction,
    cellRenderedFunction,
    height,
    disableHeight,
    disableWidth,
    borderWidth,
    ...rest
  } = props;

  const tableRef = useRef();

  const [items, setItems] = useState(data);
  const [asc, setAsc] = useState(true);
  const [order, setOrder] = useState();
  // mapStateToProps
  const lg = useSelector((state: StoreState) => state.content.lg);

  const setSort = options => {
    const { sortBy } = options;
    if (order !== sortBy) {
      setAsc(true);
      setOrder(sortBy);
    } else {
      setAsc(!asc);
    }
  };

  useEffect(() => {
    if (!order) return;

    const ordered = orderBy(
      data,
      item => {
        const val = get(item, order);
        /* eslint-disable */

        if (new Date(val) != 'Invalid Date') return new Date(val).getTime();
        /* eslint-enable */
        if (!isNaN(val)) return parseFloat(val);
        if (typeof val === 'string') return val.toUpperCase();
        // case multilingual
        if (typeof val === 'object' && typeof val[lg] === 'string') return val[lg].toUpperCase();
        return '';
      },
      asc ? 'asc' : 'desc',
    );
    setItems(ordered);
  }, [asc, order]);

  /**
   * Header
   */
  const headerRowRenderer = headerRowProps => {
    const { className, columns, style } = headerRowProps;
    return (
      <div className={styles('header-row', headerRowClassName, className)} role="row" style={style}>
        {columns}
      </div>
    );
  };

  const headerContentRendered = headerProps => {
    const { dataKey, disableSort, label } = headerProps;

    if (headerRendererFunction) {
      const rendered = headerRendererFunction(headerProps);
      if (rendered) return rendered;
    }

    return (
      <>
        <TextItem path={label} />

        {!disableSort && order === dataKey && (
          <div className={styles('sorter')}>
            {asc ? (
              <CgSortZa className={styles('icon')} />
            ) : (
              <CgSortAz className={styles('icon')} />
            )}
          </div>
        )}
      </>
    );
  };

  const headerRenderer = headerProps => {
    const { columnData } = headerProps;

    return (
      <div className={styles('header', columnData.key, headerClassName)}>
        {headerContentRendered(headerProps)}
      </div>
    );
  };

  // Cells

  const renderText = (value: string, columnData) => {
    const type = columnData.type;

    // handle date type
    if (type === 'date') {
      return <DateItem date={value} format={columnData.format} />;
    }

    // All other case
    if (Array.isArray(value)) {
      return value.map((val, index) => (
        <span key={index}>
          {index > 0 && <span>,&nbsp;</span>}
          {renderText(val, columnData)}
        </span>
      ));
    }
    if (columnData.list) {
      return <TextItem list={columnData.list} item={value} />;
    }
    if (columnData.values) {
      return <TextItem path={columnData.values} item={value} />;
    }

    return <TextItem path={value} isHtml={columnData.isHtml} />;
  };

  const cellContentRenderer = cellProps => {
    // from virtual
    const { cellData, columnData } = cellProps;

    if (cellRenderedFunction) {
      const rendered = cellRenderedFunction(cellProps);
      if (rendered) return rendered;
    }

    return renderText(cellData, columnData);
  };

  const cellRenderer = cellProps => {
    const { columnData } = cellProps;

    return (
      <div className={styles('cell-container', columnData.key, cellClassName)}>
        {cellContentRenderer(cellProps)}
      </div>
    );
  };

  const getColumnWidth = headerItem => {
    if (headerItem.width) return headerItem.width;

    if (headerItem.minWidth) return headerItem.minWidth;

    return 150;
  };

  // Doc
  // https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md

  return (
    <div className={styles('custom-virtual-table', tableClassName)}>
      <AutoSizer disableHeight={disableHeight} disableWidth={disableWidth}>
        {autoSizerProps => {
          const tabletHeight = height || autoSizerProps.height;
          const tableWidth = Math.max(autoSizerProps.width, forcedWidth || 0);

          if (!tableWidth || !tabletHeight) return false;

          return (
            <Table
              ref={tableRef}
              {...rest}
              headerRowRenderer={headerRowRenderer}
              // do not apply style on table if you use AutoSizer
              className={styles('table')}
              rowClassName={styles('row', rowClassName)}
              width={tableWidth - 2 * (borderWidth || 0)}
              height={tabletHeight - 2 * (borderWidth || 0)}
              headerHeight={headerHeight || 50}
              rowHeight={rowHeight || 60}
              sort={setSort}
              sortBy={order}
              sortDirection={asc ? SortDirection.ASC : SortDirection.DESC}
              rowCount={items.length}
              rowGetter={({ index }) => items[index]}
            >
              {headers &&
                headers
                  .filter(e => !e.hide)
                  .map((headerItem, index) => {
                    const dataKey = headerItem.key || headerItem.title || headerItem.label;
                    return (
                      <Column
                        key={headerItem.id || index}
                        headerRenderer={headerRenderer}
                        disableSort={headerItem.disableSort}
                        columnData={headerItem}
                        flexGrow={1}
                        label={headerItem.title}
                        minWidth={headerItem.minWidth}
                        width={getColumnWidth(headerItem)}
                        maxWidth={headerItem.maxWidth}
                        dataKey={dataKey}
                        cellRenderer={cellRenderer}
                      />
                    );
                  })}
            </Table>
          );
        }}
      </AutoSizer>
    </div>
  );
};

export default CustomVirtualTable;
