import {
  flexRender,
  getCoreRowModel,
  getPaginationRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { Table } from "@mantine/core";
import { DataTableProps } from "./types";
import { DataTableSkeleton } from "./skeleton";
import { DataTableError } from "./error";
import { DataTableFooter } from "./footer";

export function DataTable<TData, TValue>({
  columns,
  data,
  status,
  onRowClick,
  tableOptions,
  pagination,
  footer,
  footerClassName,
  containerClassName,
  error,
  emptyMessage,
}: DataTableProps<TData, TValue>) {
  const { state, ...otherOptions } = tableOptions ?? {};
  const baseState = state ?? {};
  if (pagination) {
    baseState.pagination = {
      pageIndex: pagination.pageIndex ?? 0,
      pageSize: pagination.pageSize ?? 1,
    };
  }
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),

    manualPagination: true,
    ...(pagination && {
      getPaginationRowModel: getPaginationRowModel(),
      pageCount: pagination.pageCount,
    }),
    state: baseState,
    ...otherOptions,
  });

  return (
    <>
      <div className={containerClassName}>
        <Table>
          <Table.Thead>
            {table.getHeaderGroups().map((headerGroup) => (
              <Table.Tr key={headerGroup.id}>
                {headerGroup.headers.map((header) => {
                  return (
                    <Table.Th
                      key={header.id}
                      className={
                        (header.column.columnDef.meta as Record<string, any>)
                          ?.headerClassName ?? ""
                      }
                      style={{ width: `${header.getSize()}px` }}
                    >
                      {header.isPlaceholder
                        ? null
                        : flexRender(
                          header.column.columnDef.header,
                          header.getContext(),
                        )}
                    </Table.Th>
                  );
                })}
              </Table.Tr>
            ))}
          </Table.Thead>
          <Table.Tbody>
            {status === "loading" && <DataTableSkeleton table={table} />}
            {status === "error" && (
              <DataTableError
                table={table}
                message={error?.message ?? "Something went wrong"}
                description={error?.description ?? "Please try again"}
                onRetry={error?.onRetry}
              />
            )}
            {status === "success" &&
              (table.getRowModel().rows?.length ? (
                table.getRowModel().rows.map((row) => (
                  <Table.Tr
                    key={row.id}
                    data-state={row.getIsSelected() && "selected"}
                    onClick={(event) => {
                      if (!onRowClick) return;
                      const target = event.target as HTMLElement;
                      if (
                        target.closest(
                          [
                            "button",
                            "a",
                            "input",
                            "textarea",
                            "select",
                            "[role='menu']",
                            "[role='menuitem']",
                            "[data-slot='dialog-content']",
                            "[data-slot='dialog-overlay']",
                            "[data-slot='dropdown-menu-content']",
                            "[data-stop-row-click]",
                          ].join(","),
                        )
                      ) {
                        return;
                      }
                      onRowClick(row.original);
                    }}
                    role={onRowClick ? "button" : ""}
                    className={
                      onRowClick
                        ? "cursor-pointer hover:bg-accent hover:text-foreground "
                        : ""
                    }
                  >
                    {row.getVisibleCells().map((cell) => (
                      <Table.Td
                        key={cell.id}
                        className={
                          (cell.column.columnDef.meta as Record<string, any>)
                            ?.cellClassName ?? ""
                        }
                      >
                        {flexRender(
                          cell.column.columnDef.cell,
                          cell.getContext(),
                        )}
                      </Table.Td>
                    ))}
                  </Table.Tr>
                ))
              ) : (
                <Table.Tr>
                  <Table.Td
                    colSpan={table.getVisibleFlatColumns().length}
                    className="h-24 text-center"
                  >
                    {emptyMessage ?? "No data"}
                  </Table.Td>
                </Table.Tr>
              ))}
          </Table.Tbody>
        </Table>
      </div>

      {pagination && (
        <div className={footerClassName}>
          {footer ? (
            footer({ table, pagination })
          ) : (
            <DataTableFooter table={table} pagination={pagination} />
          )}
        </div>
      )}
    </>
  );
}
