import React from "react";
import { orderBy } from 'natural-orderby';
import { MouseEventHandler, useState } from "react";
import { IKey } from "../interfaces/IKey";

export interface ITableTdCallback {(u_key: string, key: string, row: any, data: string | null): JSX.Element};
export type THeader = { key: string; label: string; visible?: boolean; callback?: ITableTdCallback };

type TSortOrder = "ascn" | "desc";


function SortButton({
  sortOrder,
  columnKey,
  sortKey,
  onClick,
}: {
  sortOrder: TSortOrder;
  columnKey: string;
  sortKey: string;
  onClick: MouseEventHandler<HTMLButtonElement>;
}) {
  return (
    <button
      onClick={onClick}
      className={`${
        sortKey === columnKey && sortOrder === "desc"
          ? "sort-button sort-reverse"
          : "sort-button"
      }`}
    >
      ▲
    </button>
  );
}

export default function SortableTable<T extends IKey>({ headers, dataTbl }: 
  { headers: THeader[], dataTbl: T[] }) 
{
  const [sortKey, setSortKey] = useState<string>(headers[0].key);
  const [sortOrder, setSortOrder] = useState<TSortOrder>("ascn");

  var sortedData: T[] = sortData(
      { 
        tableData: dataTbl, 
        sortKey: sortKey,
        reverse: sortOrder === "desc"
      });

  function changeSort(key: string) 
  {
    setSortOrder(sortOrder === "ascn" ? "desc" : "ascn");

    setSortKey(key);
  }

  function sortData(
  {
    tableData,
    sortKey,
    reverse,
  }: 
  {
    tableData: T[];
    sortKey: string;
    reverse: boolean;
  }) 
  {
    if (!sortKey) return tableData;
  
    const order = reverse ? 'asc': 'desc';
    const reval: T[] = orderBy(tableData, [sortKey], [order]);
    return reval;
  }

  function TableTd({ item, u_key, row_item, data } 
    : {item: THeader, u_key: string, row_item: T, data: string | null})
  {
    var val_complete: JSX.Element = <></>;
    if(item.visible === undefined || item.visible === true)
    {
      if(item.callback)
      {
        val_complete = item.callback(u_key, item.key, row_item, data);
      }
      else
      {
        val_complete = (<td key={u_key}>{data}</td>);
      }
    }
    return val_complete;
  }
  
  function TableTr(
    {headers, row_item}: 
    { 
      headers: THeader[], 
      row_item: T
    })
  {
    return(
      <tr key={row_item.key}>
      {
        headers.map((h_item, key) => 
        {
          var c: any = row_item; // workaround TS2322 TS7053
          var unique_key: string = row_item.key + "_" + key; 
          return ( <TableTd item={h_item} u_key={unique_key} row_item={row_item} data={c[h_item.key]}></TableTd> );
        })
      }
      </tr>
    );
  }

  function tableBody(headers: THeader[], tableDataSorted : any)
  {
    var body: JSX.Element[] = [];

    for(var flight of tableDataSorted)
    {
      body.push(
        <TableTr headers={headers} row_item = {flight} />
        );
    }

    return(
      <tbody>
      {body}
      </tbody>
    );
  }
  
  function tableHeader(headers: THeader[])
  {
    return(
      headers.map(
      (row) => 
      {
        if(row.visible === undefined || row.visible === true)
        {
          return (
            <td key={row.key}>
              {row.label}{" "}
              <SortButton
                columnKey={row.key}
                onClick={() => changeSort(row.key)}
                {...{
                  sortOrder,
                  sortKey,
                }}
              />
            </td>
          );
        }
        else
        {
          return (<></>);
        }
      }
      ));
  }

  return (
    <table key='SortTable' className='sortable'>
      <thead key='SortTableHead'>
        <tr key='SortTableHeadRow'>
          {tableHeader(headers)}
        </tr>
      </thead>
      {
        tableBody( headers, sortedData )
      }
    </table>
  );
}
