import { getStatic, typeCheck } from '@/utils';
import clsx from 'clsx';
import { useMemo, useCallback } from '@wordpress/element';
import type { CSSProperties, ReactNode } from 'react';
import { Pagination, PaginationProps } from '../pagination';
import { CheckboxControl } from '@wordpress/components';
import uniqBy from 'lodash.uniqby';

export interface TableColumnItem<
  T extends Record<string, any> = Record<string, any>,
> {
  title: string;
  key: Extract<keyof T, string> | (string & {});
  align?: 'left' | 'right' | 'center';
  width?: string;
  render?: (record: T, index: number, dataSource: T[]) => ReactNode;
}

interface TableProps<T extends Record<string, any>> {
  rowKey: string;
  dataSource: T[];
  columns: TableColumnItem<T>[];
  pagination?: PaginationProps | false;
  style?: CSSProperties;
  className?: string;
  selectable?: boolean;
  selectedList?: T[];
  onSelectedList?: (list: T[]) => void;
}

const PREFIX = 'lks-table';

const TableEmpty = () => (
  <div className={`${PREFIX}__tbody__empty`}>
    <img
      src={getStatic('/images/no-data.png')}
      className={`${PREFIX}__tbody__empty__img`}
    />
    <p className={`${PREFIX}__tbody__empty__text`}>No Data</p>
  </div>
);

export const Table = <T extends Record<string, any> = Record<string, any>>({
  rowKey,
  dataSource = [],
  columns,
  className,
  pagination,
  selectable,
  selectedList = [],
  onSelectedList,
  style = {},
}: TableProps<T>) => {
  const isEmptyTable = useMemo(
    () => !Array.isArray(dataSource) || !dataSource.length,
    [dataSource],
  );

  const isAllChecked = useMemo(() => {
    if (!dataSource.length || !selectedList.length) return false;
    return !dataSource.find(
      item =>
        !selectedList.find(
          selectedItem => selectedItem[rowKey] === item[rowKey],
        ),
    );
  }, [selectedList, dataSource]);

  const getIsChecked = useCallback(
    (item: T) => {
      return !!selectedList.find(
        selectedItem => selectedItem[rowKey] == item[rowKey],
      );
    },
    [selectedList],
  );

  const handleCheckAll = useCallback(
    (checked: boolean) => {
      if (checked) {
        onSelectedList?.(uniqBy([...selectedList, ...dataSource], rowKey));
      } else {
        onSelectedList?.(
          selectedList.filter(
            selectedItem =>
              !dataSource.find(item => item[rowKey] === selectedItem[rowKey]),
          ),
        );
      }
    },
    [selectedList, dataSource],
  );

  const handleCheckItem = useCallback(
    (checked: boolean, item: T) => {
      if (checked) {
        onSelectedList?.(uniqBy([...selectedList, item], rowKey));
      } else {
        onSelectedList?.(
          selectedList.filter(
            selectedItem => selectedItem[rowKey] !== item[rowKey],
          ),
        );
      }
    },
    [selectedList],
  );

  return (
    <div>
      <table className={clsx(PREFIX, className)} style={style}>
        <thead className={`${PREFIX}__thead`}>
          <tr className={`${PREFIX}__thead__tr ${PREFIX}__tr`}>
            {selectable && (
              <th className={clsx(`${PREFIX}__thead__tr__th`, `${PREFIX}__th`)}>
                <CheckboxControl
                  checked={isAllChecked}
                  onChange={handleCheckAll}
                />
              </th>
            )}
            {columns.map(column => (
              <th
                key={`${column.title}-${column.key}`}
                className={clsx(`${PREFIX}__thead__tr__th`, `${PREFIX}__th`, {
                  [`${PREFIX}__th--align-${column.align}`]: column.align,
                })}
                style={{
                  width: column.width || 'auto',
                }}
              >
                {column.title}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className={`${PREFIX}__tbody`}>
          {!isEmptyTable ? (
            dataSource.map((dataItem, dataIndex) => (
              <tr
                key={dataItem[rowKey]}
                className={`${PREFIX}__tbody__tr ${PREFIX}__tr`}
              >
                {selectable && (
                  <td
                    className={clsx(
                      `${PREFIX}__thead__tr__td`,
                      `${PREFIX}__td--align-center`,
                      `${PREFIX}__td`,
                    )}
                  >
                    <CheckboxControl
                      checked={getIsChecked(dataItem)}
                      onChange={checked => handleCheckItem(checked, dataItem)}
                    />
                  </td>
                )}
                {columns.map(column => {
                  const dataValue = dataItem[column.key];
                  const renderNode = column.render
                    ? column.render(dataItem, dataIndex, dataSource)
                    : dataValue;
                  const columnRender =
                    typeCheck(renderNode, ['string', 'undefined', 'object']) &&
                    !renderNode
                      ? '-'
                      : renderNode;
                  const mapKey = typeCheck(dataValue, ['string', 'number'])
                    ? dataValue
                    : `${column.title}-${column.key}`;
                  return (
                    <td
                      key={mapKey}
                      className={clsx(
                        `${PREFIX}__tbody__tr__td`,
                        `${PREFIX}__td`,
                        {
                          [`${PREFIX}__td--align-${column.align}`]:
                            column.align,
                        },
                      )}
                      style={{
                        width: column.width || 'auto',
                      }}
                    >
                      {columnRender}
                    </td>
                  );
                })}
              </tr>
            ))
          ) : (
            <tr
              className={clsx(
                `${PREFIX}__tbody__tr__td`,
                `${PREFIX}__tbody__tr__td--empty`,
                `${PREFIX}__td`,
              )}
            >
              <td colSpan={columns.length + Number(selectable)}>
                <TableEmpty />
              </td>
            </tr>
          )}
        </tbody>
      </table>
      {pagination && (
        <div className={`${PREFIX}__footer`}>
          <div className={`${PREFIX}__footer__total`}>
            Total {pagination.total} items
          </div>
          <Pagination {...pagination} />
        </div>
      )}
    </div>
  );
};
