import type { SortKey } from 'hooks/useDataControl';
import { useState, useEffect } from 'react';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { ArrowUpDown } from 'lucide-react';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { useDataControl, type UseDataControlReturn } from 'hooks/useDataControl';
import { PaginationBar } from './PaginationBar';
import { cn } from 'helpers/cn';

export const DataTable = <T,>(props: DataTableProps<T>) => {
  const [columns, setColumns] = useState<Column<T>[]>([]);
  const { dataController, uniqueKey, noDataCTA, noDataMessage } = props;
  const theUniqueKey = uniqueKey || 'id';
  const { rawData, data, pageSize, sortBy, sortedBy, setCustomSort } = dataController;

  useEffect(() => {
    if (props.columns) {
      setColumns(props.columns);
    } else if (!!rawData && rawData.length > 0) {
      const cols: Column<T>[] = Object.keys(rawData[0] as object).map((key) => ({
        field: key as keyof T,
        label: toLabel(key),
        sortKey: key as SortKey<T>,
      }));
      setColumns(cols);
    } else {
      setColumns([]);
    }
  }, [props.columns, rawData]);

  useEffect(() => {
    if (typeof props.pageSize === 'number') {
      dataController.setPageSize(props.pageSize);
    }
  }, [props.pageSize]);

  useEffect(() => {
    if (!!props.customSort) {
      setCustomSort(() => props.customSort!);
    }
  }, [props.customSort]);

  useEffect(() => {
    if (props.searchKeys) {
      const propsSearchKeys = JSON.stringify(props.searchKeys);
      const controllerSearchKeys = JSON.stringify(dataController.searchKeys);
      if (propsSearchKeys !== controllerSearchKeys) {
        dataController.setSearchKeys(props.searchKeys);
      }
    } else if (columns.length > 0 && !dataController.searchKeys) {
      const colFields = columns.map((col) => col.field).filter((f): f is keyof T => !!f);
      dataController.setSearchKeys(colFields);
    }
  }, [props.searchKeys, columns.length]);

  if (!rawData) return null;

  if (rawData.length === 0) {
    return (
      <div className="py-12 text-center">
        <div className="text-muted-foreground">{noDataMessage || 'No Data Found.'}</div>
        {noDataCTA && <>{noDataCTA}</>}
      </div>
    );
  }

  return (
    <div className="bg-card overflow-hidden rounded-xl border">
      <div>
        <Table>
          <TableHeader className="bg-muted/50">
            <TableRow>
              {columns.map((column: Column<T>, idx: number) => {
                const { label = '', sortKey, field, condition = true } = column;
                const { tooltip, headerClassName, labelMobile } = column;
                const renderColumn = typeof condition === 'function' ? condition() : condition;
                return (
                  renderColumn && (
                    <TableHead className={cn('whitespace-nowrap max-[499px]:px-2', headerClassName)} key={idx}>
                      <TooltipProvider>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <div
                              className={cn(
                                'flex items-center',
                                sortKey && 'cursor-pointer hover:text-black',
                                sortedBy?.startsWith(`${String(sortKey)}-`) && 'text-black',
                              )}
                              onClick={() => sortBy(sortKey as Extract<keyof T, string> | undefined)}
                            >
                              <span className="hidden min-[500px]:inline">
                                {String(label || field || '')} {tooltip ? <sup>ⓘ</sup> : ''}
                              </span>
                              <span className="min-[500px]:hidden">
                                {String(labelMobile || label || field || '')} {tooltip ? <sup>ⓘ</sup> : ''}
                              </span>
                              {sortKey && <ArrowUpDown className={cn('ml-2 h-4 w-4')} />}
                            </div>
                          </TooltipTrigger>
                          {tooltip && (
                            <TooltipContent>
                              <p className="whitespace-pre-line">{tooltip}</p>
                            </TooltipContent>
                          )}
                        </Tooltip>
                      </TooltipProvider>
                    </TableHead>
                  )
                );
              })}
            </TableRow>
          </TableHeader>
          <TableBody>
            {data?.map((item: T, idx: number) => {
              return (
                <TableRow key={String(item[theUniqueKey as keyof T] || idx)} className="group/tablerow">
                  {columns.map((column, idx) => {
                    const value = column.field !== undefined ? item[column.field] : undefined;
                    const { format, condition = true, cellClassName } = column;
                    const renderColumn = typeof condition === 'function' ? condition() : condition;
                    return (
                      renderColumn && (
                        <TableCell className={cn('whitespace-nowrap max-[499px]:px-2', cellClassName)} key={idx}>
                          <>
                            {format
                              ? column.field !== undefined
                                ? format({
                                    value: item[column.field],
                                    item,
                                    data,
                                    idx,
                                  })
                                : format({
                                    value: undefined as unknown as T[keyof T],
                                    item,
                                    data,
                                    idx,
                                  })
                              : value}
                          </>
                        </TableCell>
                      )
                    );
                  })}
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
      </div>
      {!!pageSize && pageSize < rawData?.length && (
        <PaginationBar dataManager={dataController as UseDataControlReturn<T>} />
      )}
    </div>
  );
};

export { useDataControl };
export type { UseDataControlReturn };

type DataTableProps<T> = {
  dataController: UseDataControlReturn<T>;
  columns?: Column<T>[];
  uniqueKey?: keyof T;
  searchKeys?: (keyof T)[];
  pageSize?: number;
  noDataCTA?: React.ReactNode;
  customSort?: (a: T, b: T, originalSort: (a: T, b: T) => number) => number;
  noDataMessage?: string;
};

export type DataTableFormatArgs<T> = {
  value: T[keyof T];
  item: T;
  data: T[];
  idx: number;
};

export type Column<T> = {
  field?: keyof T;
  label?: string;
  labelMobile?: string;
  headerClassName?: string;
  cellClassName?: string;
  format?: (args: DataTableFormatArgs<T>) => React.ReactNode;
  condition?: boolean | (() => boolean);
  sortKey?: SortKey<T>;
  tooltip?: string;
};

function toLabel(key: string): string {
  return key
    .replace(/([a-z0-9])([A-Z])/g, '$1 $2') // insert space before capitals
    .replace(/_/g, ' ') // replace underscores with spaces
    .replace(/\s+/g, ' ') // collapse multiple spaces
    .trim()
    .replace(/\w\S*/g, (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
}
