'use client';
import React, {
  useState,
  useMemo,
  useContext,
  useCallback,
  createContext,
  PropsWithChildren
} from 'react';
import {
  useReactTable,
  getCoreRowModel,
  type ColumnDef,
  type Table
} from '@tanstack/react-table';
import { Checkbox } from '@/components/ui/checkbox';

export type ResourceItem = {
  [key: string]: string | number | null | undefined | ResourceItem;
};

type ResourceListContextType<T = unknown> = {
  data: T[];
  page: number;
  total: number;
  columns: ColumnDef<T>[];
  table: Table<T>;
  registerColumn: (column: ColumnDef<T>) => void;
  unregisterColumn: (columnId: string) => void;
};

export const ResourceListContext = createContext<ResourceListContextType>({
  data: [],
  page: -1,
  total: 0,
  columns: [],
  table: null!,
  registerColumn() {},
  unregisterColumn() {}
});

export const useResourceList = <T extends object = object>() => {
  return useContext(ResourceListContext) as ResourceListContextType<T>;
};

type Props<T = ResourceItem> = PropsWithChildren<{
  selection?: boolean;
  data: T[];
  total: number;
  page: number;
  perPage: number;
  orderBy?: string;
  orderDir?: string;
  onOrderByChange?: (orderBy?: string) => void;
  onOrderDirChange?: (orderDir?: 'asc' | 'desc') => void;
  onPerPageChange?: (perPage: number) => void;
  onPageChange?: (page: number) => void;
}>;

export const ResourceListProvider = <T = ResourceItem>(props: Props<T>) => {
  const {
    data,
    selection,
    perPage,
    page,
    total,
    orderDir,
    orderBy,
    children,
    onOrderByChange,
    onOrderDirChange,
    onPerPageChange,
    onPageChange
  } = props;

  const [columns, setColumns] = useState<ColumnDef<T>[]>(
    selection
      ? [
          {
            id: '__select__',
            header({ table }) {
              return (
                <Checkbox
                  className='translate-y-0.5'
                  aria-label='Select all'
                  checked={
                    table.getIsAllPageRowsSelected() ||
                    (table.getIsSomePageRowsSelected() && 'indeterminate')
                  }
                  onCheckedChange={(value) =>
                    table.toggleAllPageRowsSelected(!!value)
                  }
                />
              );
            },
            cell: ({ row }) => {
              return (
                <Checkbox
                  className='translate-y-0.5'
                  aria-label='Select row'
                  checked={row.getIsSelected()}
                  onCheckedChange={(value) => row.toggleSelected(!!value)}
                />
              );
            },
            enableSorting: false,
            enableHiding: false,
            size: 40
          }
        ]
      : []
  );

  const sorting = useMemo(() => {
    return orderBy && orderDir
      ? [
          {
            id: orderBy,
            desc: orderDir === 'desc'
          }
        ]
      : [];
  }, [orderBy, orderDir]);

  const pagination = useMemo(() => {
    return {
      pageIndex: page,
      pageSize: perPage
    };
  }, [page, perPage]);

  const table = useReactTable<T>({
    columns,
    data,
    state: {
      pagination,
      sorting
    },
    pageCount: total > 0 ? Math.ceil(total / perPage) - 1 : 0,
    getCoreRowModel: getCoreRowModel(),
    enableRowSelection: true,
    manualSorting: true,
    manualPagination: true,
    manualFiltering: true,
    getRowId: (row) => (row as unknown as { id: string }).id,
    onSortingChange(updater) {
      const [sort] = typeof updater === 'function' ? updater(sorting) : updater;

      if (sort) {
        if (sort.id !== orderBy && onOrderByChange) {
          onOrderByChange(sort.id);
        }

        if (orderDir !== (sort.desc ? 'desc' : 'asc') && onOrderDirChange) {
          onOrderDirChange(sort.desc ? 'desc' : 'asc');
        }
      } else {
        if (onOrderByChange) {
          onOrderByChange('');
        }

        if (onOrderDirChange) {
          onOrderDirChange('asc');
        }
      }
    },
    onPaginationChange(updater) {
      const { pageIndex, pageSize } =
        typeof updater === 'function' ? updater(pagination) : updater;

      if (pagination.pageIndex !== pageIndex && onPageChange) {
        onPageChange(pageIndex);
      }

      if (pagination.pageSize !== pageSize && onPerPageChange) {
        onPerPageChange(pageSize);
      }
    }
  });

  const registerColumn = useCallback((column: ColumnDef<T>) => {
    setColumns((columns) => {
      if (columns.find((c) => c.id === column.id)) {
        return columns;
      }

      return [...columns, column];
    });
  }, []);

  const unregisterColumn = useCallback((columnId: string) => {
    setColumns((columns) => {
      return columns.filter((c) => c.id !== columnId);
    });
  }, []);

  return (
    <ResourceListContext.Provider
      value={
        {
          data,
          total,
          columns,
          table,
          registerColumn,
          unregisterColumn
        } as ResourceListContextType
      }
    >
      {children}
    </ResourceListContext.Provider>
  );
};
