import React, { useEffect, useState, MouseEvent } from 'react';
import { Table, TableProps as BootstrapTableProps } from 'react-bootstrap';
import Paginations, {PaginationsProps} from '@molecules/Paginations/Paginations';
import Select from '@atoms/Select/Select';

const PAGE_SIZE_OPTIONS: {id: number; name: number; disabled?: boolean;}[] = [
  {
    id: 5,
    name: 5,
  },
  {
    id: 10,
    name: 10
  },
  {
    id: 20,
    name: 20
  },
  {
    id: 50,
    name: 50
  },
  {
    id: 100,
    name: 100
  },
];

const DEFAULT_PAGE_SIZE = 10;

const DEFAULT_PAGINATIONS_PROPS = {
  config: 5,
  size: 'sm',
  pageSize: DEFAULT_PAGE_SIZE,
  pageSizeOptions: PAGE_SIZE_OPTIONS,
  renderTotalText: (length: string) => (`Total: ${length}`)
};

const PAGINATIONS_SIZE = {
  sm: 'form-select-sm',
  lg: 'form-select-lg',
}

interface Column {
  title: string;
  dataIndex: string;
  render?: (value: any, row: any) => React.ReactNode;
}

interface TablesProps extends Omit<BootstrapTableProps, "onChange"> {
  data: Array<Object>;
  columns: Array<Column>;
  rowKey: string;
  value: string;
  onChange: (value: string, event: React.MouseEvent, rowData: Object) => void;
  ellipsis: boolean;
  className: string;
  maxHeight: string;
  theadClassName: string;
  pagination: boolean;
  PaginationsProps: PaginationsProps;
  renderDataNotFound: (className: string) => React.ReactNode;
  size?: 'sm' | 'lg';
}

const Tables = ({
  data: initData,
  columns,
  rowKey,
  value,
  onChange,
  ellipsis,
  className,
  maxHeight,
  theadClassName,
  pagination,
  PaginationsProps: initPaginationsProps,
  renderDataNotFound,
  variant,
  ...props
}: TablesProps) => {
  const { pageSizeOptions, renderTotalText, ...PaginationsProps } = Object.assign(DEFAULT_PAGINATIONS_PROPS, initPaginationsProps);
  const [pageSize, setPageSize] = useState(PaginationsProps.pageSize);
  const [activeIndex, setActiveIndex] = useState(0);
  const [data, setData] = useState(pagination ? initData?.slice(0, pageSize) : initData);
  const isEmpty = initData?.length <= 0;

  const freshData = () => {
    const totalPage = Math.ceil(initData?.length / pageSize);
    handleChangePage(Math.min(activeIndex, totalPage - 1), pageSize);
  }

  useEffect(() => {
    if (pagination) {
      freshData();
    }
  }, [initData, pagination]);

  const handleOnChange = (val: any, item: any) => (e: MouseEvent) => {
    onChange(val, e, item);
  }

  const handleChangePage = (value: any, vPageSize = pageSize) => {
    setActiveIndex(value);
    const start = value * vPageSize;
    const newData = initData?.slice(start, start + vPageSize);
    setData(newData);
  }

  const handlePageSize = (value: any) => {
    const vPageSize = Number(value);
    setActiveIndex(0);
    setPageSize(vPageSize);
    handleChangePage(0, vPageSize);
  }

  return (
    <div className='table-container'>
      <div className={maxHeight ? 'table-scroll' : ''} style={{ maxHeight }}>
        <Table className={`${className} ${ellipsis ? 'table-ellipsis' : ''}`} {...props}>
          <thead className={theadClassName}>
            <tr>
              {
                pagination && (
                  <th className={`center ${variant && `th-${variant}`}`}>#</th>
                )
              }

              {
                columns?.map((col: any) => {
                  return (
                    <th className={`${variant && `th-${variant}`}`} key={col.dataIndex}>{col.title}</th>
                  )
                })
              }
            </tr>
          </thead>
          <tbody>
            {isEmpty && (
              <tr>
                <td colSpan={columns?.length + 1}>{renderDataNotFound(PAGINATIONS_SIZE[props.size ?? 'sm'])}</td>
              </tr>
            )}
            {
              (pagination ? data : initData)?.map((item: any, rowIndex) => {
                const id = item[rowKey];
                const trClassName = id === value ? 'tables-item-selected' : '';
                return (
                  <tr key={id} className={trClassName} onClick={handleOnChange(id, item)}>
                    {
                      pagination && (
                        <td className={`center ${trClassName}`}>
                          {activeIndex * pageSize + rowIndex + 1}
                        </td>
                      )
                    }

                    {
                      columns?.map((col: any) => {
                        const { render, dataIndex } = col;
                        let label = item[dataIndex];

                        if (typeof render === 'function') {
                          label = render(id, { ...item, rowIndex });
                        }

                        return (
                          <td title={(typeof label === 'string') ? label : undefined} key={`${id}${dataIndex}`} className={trClassName}>
                            {label}
                          </td>
                        )
                      })
                    }
                  </tr>
                )
              })
            }
          </tbody>
        </Table>
      </div>
      {
        (pagination && !isEmpty) && (
          <div className='table-paginations'>
            <span
              className={PAGINATIONS_SIZE[PaginationsProps.size]}
            >
              {renderTotalText(initData?.length.toString())}
            </span>
            <span>
              <Select
                data={pageSizeOptions}
                onChange={handlePageSize}
                value={`${pageSize}`}
                size={PaginationsProps.size}
              />
            </span>
            <Paginations
              {...PaginationsProps}
              count={initData?.length}
              activeIndex={activeIndex}
              onChange={handleChangePage}
              pageSize={pageSize}
            />
          </div>
        )
      }
    </div>
  );
};

export default Tables;
export { Tables, TablesProps, Column };