"use client"

import {
  ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table"

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"
import { cn } from "@/lib/utils";
import Pagination from "./pagination";

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
  variant?: "dashboard" | "default";
  onRowSelectStateChange: Dispatch<SetStateAction<TData[]>>;
  selectedRows?: TData[];
  onRowClick?: (row: TData) => void;
  page?: number;
  pageCount?: number;
  onPageChange?: (page: number) => void;
}

export function DataTable<TData, TValue>({
  columns,
  data,
  variant,
  onRowSelectStateChange,
  selectedRows,
  onRowClick,
  page,
  pageCount,
  onPageChange,
}: DataTableProps<TData, TValue>) {

  const [rowSelection, setRowSelection] = useState({})
  const previousSelectedRowsRef = useRef<TData[]>([])

  // Update rowSelection based on selectedRows and current page data
  useEffect(() => {
    if (!selectedRows || !data) return;

    const newSelection: Record<string, boolean> = {};
    data.forEach((item, index) => {
      const isSelected = selectedRows.some(selectedItem => {
        // Check if both items have an 'id' property for comparison
        if (typeof selectedItem === 'object' && selectedItem !== null && 'id' in selectedItem &&
            typeof item === 'object' && item !== null && 'id' in item) {
          return (selectedItem as any).id === (item as any).id;
        }
        // Fallback to JSON comparison if no id
        return JSON.stringify(selectedItem) === JSON.stringify(item);
      });
      if (isSelected) {
        newSelection[index.toString()] = true;
      }
    });

    // Only update if the selection actually changed
    const hasChanged = JSON.stringify(newSelection) !== JSON.stringify(rowSelection);
    if (hasChanged) {
      setRowSelection(newSelection);
    }
  }, [selectedRows, data]);
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    onRowSelectionChange: setRowSelection,
    state: {
      rowSelection,
    },
  })

  const tableHeadVariants = {
    dashboard: "font-bold text-[12px] leading-[140%] bg-[#F7F7FC] hover:bg-[#F7F7FC] text-[#2D3091]",
    default: "",
  };

  const rowVariants = {
    dashboard: `text-[14px] font-medium text-[#333333]`,
    default: "",
  };

  // Get id for selected rows
  // useEffect(() => onRowSelectStateChange?.(rowSelection), [
  //   onRowSelectStateChange,
  //   rowSelection
  // ]);

  useEffect(() => {
    const currentPageSelectedRows = table.getFilteredSelectedRowModel().rows.map(row => row.original);

    // Update the global selectedRows by removing current page items and adding newly selected ones
    if (onRowSelectStateChange && data) {
      const otherPagesSelected = previousSelectedRowsRef.current.filter(selectedItem =>
        !data.some(dataItem => {
          // Check if both items have an 'id' property for comparison
          if (typeof selectedItem === 'object' && selectedItem !== null && 'id' in selectedItem &&
              typeof dataItem === 'object' && dataItem !== null && 'id' in dataItem) {
            return (selectedItem as any).id === (dataItem as any).id;
          }
          // Fallback to JSON comparison if no id
          return JSON.stringify(dataItem) === JSON.stringify(selectedItem);
        })
      );

      const newSelectedRows = [...otherPagesSelected, ...currentPageSelectedRows];

      // Only update if the selection actually changed
      const hasChanged = JSON.stringify(newSelectedRows) !== JSON.stringify(previousSelectedRowsRef.current);
      if (hasChanged) {
        previousSelectedRowsRef.current = newSelectedRows;
        onRowSelectStateChange(newSelectedRows);
      }
    }
  }, [rowSelection, data, onRowSelectStateChange]);

  // Update ref when selectedRows prop changes externally (like page change)
  useEffect(() => {
    if (selectedRows) {
      previousSelectedRowsRef.current = selectedRows;
    }
  }, [selectedRows]);  return (
    <div className="rounded-md border">
      <Table>
        <TableHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map((header) => {
                return (
                  <TableHead key={header.id} className={cn(
                    tableHeadVariants[variant || "default"],
                  )}>
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                  </TableHead>
                )
              })}
            </TableRow>
          ))}
        </TableHeader>
        <TableBody>
          {table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row) => (
              <TableRow
                key={row.id}
                data-state={row.getIsSelected() && "selected"}
                onClick={() => { onRowClick?.(row.original) }}
                className={cn(
                  variant === "dashboard" && row.index % 2 === 0 ? "bg-white" : "bg-[#f3f3f354]",
                  rowVariants[variant || "default"]
                )}
              >
                {row.getVisibleCells().map((cell) => (
                  <TableCell key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </TableCell>
                ))}
              </TableRow>
            ))
          ) : (
            <TableRow>
              <TableCell colSpan={columns.length} className="h-24 text-center">
                No results.
              </TableCell>
            </TableRow>
          )}
        </TableBody>
      </Table>
      <div className="flex justify-between items-center p-3">
        <div className="flex-1 text-sm text-muted-foreground">
          {table.getFilteredSelectedRowModel().rows.length} of{" "}
          {table.getFilteredRowModel().rows.length} row(s) selected.
        </div>
        {/* Pagination */}
        {page !== undefined && onPageChange && pageCount !== undefined && (
          <Pagination
            page={page}
            pageCount={pageCount}
            onPageChange={onPageChange}
          />
        )}
      </div>
    </div>
  )
}
