import { createRef, useEffect, useState, useMemo } from "react";
import classNames from "classnames";
import { ArrowDropDownIcon, CopyIcon, DoneIcon } from "../Main/Icons";
import { getComparator, stableSort } from "./helpers";
import Tooltip from "../Main/Tooltip/Tooltip";
import Button from "../Main/Button/Button";
import useCopyToClipboard from "../../hooks/useCopyToClipboard";

type OrderDir = "asc" | "desc"

export interface TableColumn<T> {
  key: keyof T;
  title?: string;
  format?: (obj: T) => string;
  className?: string;
}

interface TableProps<T> {
  rows: T[];
  columns: TableColumn<T>[];
  defaultOrderBy: keyof T;
  copyToClipboard?: keyof T;
  defaultOrderDir?: OrderDir;
  rowClasses?: (obj: T) => Record<string, boolean>;
  rowAction?: (ref: React.RefObject<HTMLElement>) => () => void;
  // TODO: Remove when pagination is implemented on the backend.
  paginationOffset: {
    startIndex: number;
    endIndex: number;
  }
}

interface TableRow {
  id: string;
}

const Table = <T extends TableRow>({
  rows,
  columns,
  defaultOrderBy,
  defaultOrderDir,
  copyToClipboard,
  paginationOffset,
  rowClasses,
  rowAction = (_ref: React.RefObject<HTMLElement>) => () => {},
}: TableProps<T>) => {
  const handleCopyToClipboard = useCopyToClipboard();

  const [orderBy, setOrderBy] = useState<keyof T>(defaultOrderBy);
  const [orderDir, setOrderDir] = useState<OrderDir>(defaultOrderDir || "desc");
  const [copied, setCopied] = useState<number | null>(null);
  const [rowRefs, setRowRefs] = useState(new Map());

  useEffect(() => {
    const newRowRefs = new Map();
    rows.forEach(row => {
      newRowRefs.set(row.id, createRef());
    });
    setRowRefs(newRowRefs);
  }, [rows]);

  // const sortedList = useMemo(() => stableSort(rows as [], getComparator(orderDir, orderBy)),
  //   [rows, orderBy, orderDir]);
  // TODO: Remove when pagination is implemented on the backend.
  const sortedList = useMemo(() => {
    const { startIndex, endIndex } = paginationOffset;
    return stableSort(rows as [], getComparator(orderDir, orderBy)).slice(startIndex, endIndex);
  }, [rows, orderBy, orderDir, paginationOffset]);

  const createSortHandler = (key: keyof T) => () => {
    setOrderDir((prev) => prev === "asc" && orderBy === key ? "desc" : "asc");
    setOrderBy(key);
  };

  const createCopyHandler = (copyValue:  string | number, rowIndex: number) => async () => {
    if (copied === rowIndex) return;
    try {
      await handleCopyToClipboard(String(copyValue));
      setCopied(rowIndex);
    } catch (e) {
      console.error(e);
    }
  };

  useEffect(() => {
    if (copied === null) return;
    const timeout = setTimeout(() => setCopied(null), 2000);
    return () => clearTimeout(timeout);
  }, [copied]);

  const copyCol = copyToClipboard && columns.find((col) => col.key == copyToClipboard);

  return (
    <table className="vm-table">
      <thead className="vm-table-header">
        <tr className="vm-table__row vm-table__row_header">
          {columns.map((col) => (
            <th
              className="vm-table-cell vm-table-cell_header vm-table-cell_sort"
              onClick={createSortHandler(col.key)}
              key={String(col.key)}
            >
              <div className="vm-table-cell__content">
                <div>
                  {String(col.title || col.key)}
                </div>
                <div
                  className={classNames({
                    "vm-table__sort-icon": true,
                    "vm-table__sort-icon_active": orderBy === col.key,
                    "vm-table__sort-icon_desc": orderDir === "desc" && orderBy === col.key
                  })}
                >
                  <ArrowDropDownIcon/>
                </div>
              </div>
            </th>
          ))}
          {copyToClipboard && <th className="vm-table-cell vm-table-cell_header"/>}
        </tr>
      </thead>
      <tbody className="vm-table-body">
        {sortedList.map((row, rowIndex) => (
          <tr
            className={classNames({
              "vm-table__row": true,
              ...(rowClasses ? rowClasses(row) : {}),
            })}
            id={row.id}
            key={rowIndex}
            ref={rowRefs.get(row.id)}
            onClick={rowAction(rowRefs.get(row.id))}
          >
            {columns.map((col) => (
              <td
                className={classNames({
                  "vm-table-cell": true,
                  [`${col.className}`]: col.className
                })}
                key={String(col.key)}
              >
                {(col.format ? col.format(row) : String(row[col.key])) || "-"}
              </td>
            ))}
            {copyToClipboard && copyCol && (
              <td className="vm-table-cell vm-table-cell_right">
                {row[copyToClipboard] && (
                  <div className="vm-table-cell__content">
                    <Tooltip title={copied === rowIndex ? "Copied" : "Copy row"}>
                      <Button
                        variant="text"
                        color={copied === rowIndex ? "success" : "gray"}
                        size="small"
                        startIcon={copied === rowIndex ? <DoneIcon/> : <CopyIcon/>}
                        onClick={createCopyHandler(copyCol.format ? copyCol.format(row) : String(row[copyToClipboard]), rowIndex)}
                        ariaLabel="copy row"
                      />
                    </Tooltip>
                  </div>
                )}
              </td>
            )}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

export default Table;
