"use client";

import { useEffect, useMemo, useState } from "react";
import {
  ColumnDef,
  getCoreRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  RowSelectionState,
  SortingState,
  useReactTable,
} from "@tanstack/react-table";

import { createSelectionColumn } from "../components/table/columns/selectionColumn";
import {
  DataTableColumnDef,
  PaginationConfig,
  SortingConfig,
} from "../types/table.types";

export interface UseDataTableProps<TData extends object> {
  data: TData[];
  columns: DataTableColumnDef<TData>[];
  selectable?: boolean;
  pagination?: PaginationConfig;
  sorting?: SortingConfig;
  rowSelection?: RowSelectionState;
  onRowSelectionChange?: (state: RowSelectionState) => void;
  onSelectedRowsChange?: (rows: TData[]) => void;
  getRowId?: (row: TData) => string;
}

export function useDataTable<TData extends object>({
  data,
  columns,
  selectable,
  pagination,
  sorting,
  rowSelection,
  onRowSelectionChange,
  onSelectedRowsChange,
  getRowId,
}: UseDataTableProps<TData>) {
  const [sortingState, setSortingState] = useState<SortingState>(
    sorting?.initialState ?? [],
  );

  const [rowSelectionState, setRowSelectionState] = useState<RowSelectionState>(
    rowSelection ?? {},
  );

  const [paginationState, setPaginationState] = useState(() => ({
    pageIndex: pagination?.controller?.params.page ?? 0,
    pageSize: pagination?.controller?.params.limit ?? 10,
  }));

  const resolvedRowSelection = rowSelection ?? rowSelectionState;

  const resolvedColumns = useMemo<ColumnDef<TData, unknown>[]>(
    () => (selectable ? [createSelectionColumn<TData>(), ...columns] : columns),
    [columns, selectable],
  );

  const table = useReactTable({
    data,
    columns: resolvedColumns,
    state: {
      sorting: sorting?.state ?? sortingState,
      rowSelection: resolvedRowSelection,
      pagination: {
        pageIndex: (pagination?.controller.params.page ?? 1) - 1,
        pageSize:
          pagination?.controller.params.limit ?? paginationState.pageSize,
      },
    },

    enableRowSelection: Boolean(selectable),
    getRowId,

    manualPagination: Boolean(pagination),
    pageCount: pagination?.pageCount ?? -1,

    manualSorting: true,
    onSortingChange: (updater) => {
      const next =
        typeof updater === "function"
          ? updater(sorting?.state ?? sortingState)
          : updater;

      if (sorting?.onChange) {
        sorting.onChange(next);
      } else {
        setSortingState(next);
      }
    },
    onRowSelectionChange: onRowSelectionChange ?? setRowSelectionState,

    onPaginationChange: (updater) => {
      if (!pagination) {
        setPaginationState((prev) =>
          typeof updater === "function" ? updater(prev) : updater,
        );
        return;
      }

      const currentState = {
        pageIndex: pagination.controller.params.page - 1,
        pageSize: pagination.controller.params.limit,
      };

      const nextState =
        typeof updater === "function" ? updater(currentState) : updater;

      pagination.controller.patch({
        page: nextState.pageIndex + 1,
        limit: nextState.pageSize,
      });
    },

    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  });

  useEffect(() => {
    if (!onSelectedRowsChange) {
      return;
    }

    const selectedRows = table
      .getSelectedRowModel()
      .rows.map((row) => row.original);

    onSelectedRowsChange(selectedRows);
  }, [onSelectedRowsChange, table, resolvedRowSelection]);

  return table;
}
