"use client";

import * as React from "react";
import { Table, flexRender } from "@tanstack/react-table";
import { useVirtualizer } from "@tanstack/react-virtual";
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  DragEndEvent,
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  horizontalListSortingStrategy,
} from "@dnd-kit/sortable";
import { cn } from "@/lib/utils";
import { Loader2, ChevronRight, ChevronDown } from "lucide-react";

import { ClientTableToolbar } from "../client-table/client-table-toolbar";
import { exportToExcel } from "../client-table/export-utils";
import { ClientDataTablePagination } from "@/components/client-data-table/data-table-pagination";
import { ClientTableViewOptions } from "../client-table/client-table-view-options";

import { ClientTableColumnHeader } from "./client-table-column-header";
import { ClientTablePreset } from "./client-table-preset";
import { ClientVirtualTableProps } from "./types";

export function ClientVirtualTable<TData>({
  table,
  isLoading = false,
  height = "100%",
  estimateRowHeight = 40,
  className,
  actions,
  customToolbar,
  enableExport = true,
  onExport,
  enableUserPreset = false,
  tableKey,
  getRowClassName,
  onRowClick,
  renderHeaderVisualFeedback,
}: ClientVirtualTableProps<TData>) {
  // --- DnD Sensors ---
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8,
      },
    }),
    useSensor(KeyboardSensor)
  );

  // --- Drag Handler ---
  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (active && over && active.id !== over.id) {
      const activeId = active.id as string;
      const overId = over.id as string;

      const activeColumn = table.getColumn(activeId);
      const overColumn = table.getColumn(overId);

      if (activeColumn && overColumn) {
        const activePinState = activeColumn.getIsPinned();
        const overPinState = overColumn.getIsPinned();

        // If dragging between different pin states, update the pin state
        if (activePinState !== overPinState) {
          activeColumn.pin(overPinState);
        }

        // Reorder
        const currentOrder = table.getState().columnOrder;
        const oldIndex = currentOrder.indexOf(activeId);
        const newIndex = currentOrder.indexOf(overId);
        
        if (oldIndex !== -1 && newIndex !== -1) {
            table.setColumnOrder(arrayMove(currentOrder, oldIndex, newIndex));
        }
      }
    }
  };

  // --- Virtualization ---
  const tableContainerRef = React.useRef<HTMLDivElement>(null);
  const { rows } = table.getRowModel();

  const rowVirtualizer = useVirtualizer({
    count: rows.length,
    getScrollElement: () => tableContainerRef.current,
    estimateSize: () => estimateRowHeight,
    overscan: 10,
  });

  const virtualRows = rowVirtualizer.getVirtualItems();
  const totalSize = rowVirtualizer.getTotalSize();

  const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
  const paddingBottom =
    virtualRows.length > 0
      ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0)
      : 0;

  // --- Export ---
  const handleExport = async () => {
    if (onExport) {
      onExport(table.getFilteredRowModel().rows.map((r) => r.original));
      return;
    }
    const currentData = table.getFilteredRowModel().rows.map((row) => row.original);
    // Note: exportToExcel needs columns definition. table.getAllColumns() or visible columns?
    // Using table.getAllLeafColumns() usually.
    await exportToExcel(currentData, table.getAllLeafColumns(), `export-${new Date().toISOString().slice(0, 10)}.xlsx`);
  };

  const columns = table.getVisibleLeafColumns();
  const data = table.getFilteredRowModel().rows; // or just rows which is from getRowModel

  return (
    <div
      className={cn("flex flex-col gap-4", className)}
      style={{ height }}
    >
      <ClientTableToolbar
        globalFilter={table.getState().globalFilter ?? ""}
        setGlobalFilter={table.setGlobalFilter}
        totalRows={table.getRowCount()}
        visibleRows={table.getRowModel().rows.length}
        onExport={enableExport ? handleExport : undefined}
        viewOptions={
          <>
            <ClientTableViewOptions table={table} />
            {enableUserPreset && tableKey && (
              <ClientTablePreset table={table} tableKey={tableKey} />
            )}
          </>
        }
        customToolbar={customToolbar}
        actions={actions}
      />

      <div
        ref={tableContainerRef}
        className="relative border rounded-md overflow-auto bg-background flex-1 min-h-0"
      >
        {isLoading && (
          <div className="absolute inset-0 z-50 flex items-center justify-center bg-background/50 backdrop-blur-sm">
            <Loader2 className="h-8 w-8 animate-spin text-primary" />
          </div>
        )}

        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragEnd={handleDragEnd}
        >
          <table
            className="table-fixed border-collapse w-full min-w-full"
            style={{ width: table.getTotalSize() }}
          >
            <thead className="sticky top-0 z-40 bg-muted">
              {table.getHeaderGroups().map((headerGroup) => (
                <tr key={headerGroup.id}>
                  <SortableContext
                    items={headerGroup.headers.map((h) => h.id)}
                    strategy={horizontalListSortingStrategy}
                  >
                    {headerGroup.headers.map((header) => (
                      <ClientTableColumnHeader
                        key={header.id}
                        header={header}
                        enableReordering={true}
                        renderHeaderVisualFeedback={renderHeaderVisualFeedback}
                      />
                    ))}
                  </SortableContext>
                </tr>
              ))}
            </thead>
            <tbody>
              {paddingTop > 0 && (
                <tr>
                  <td style={{ height: `${paddingTop}px` }} />
                </tr>
              )}
              {virtualRows.length === 0 && !isLoading ? (
                <tr>
                  <td colSpan={columns.length} className="h-24 text-center">
                    No results.
                  </td>
                </tr>
              ) : (
                virtualRows.map((virtualRow) => {
                  const row = rows[virtualRow.index];

                  // --- Group Header Rendering ---
                  if (row.getIsGrouped()) {
                    const groupingColumnId = row.groupingColumnId ?? "";
                    const groupingValue = row.getGroupingValue(groupingColumnId);

                    return (
                      <tr
                        key={row.id}
                        className="hover:bg-muted/50 border-b bg-muted/30"
                        style={{ height: `${virtualRow.size}px` }}
                      >
                        <td
                          colSpan={columns.length}
                          className="px-4 py-2 text-left font-medium cursor-pointer"
                          onClick={row.getToggleExpandedHandler()}
                        >
                          <div className="flex items-center gap-2">
                            {row.getIsExpanded() ? (
                              <ChevronDown className="h-4 w-4" />
                            ) : (
                              <ChevronRight className="h-4 w-4" />
                            )}
                            <span className="flex items-center gap-2">
                              <span className="font-bold capitalize">
                                {groupingColumnId}:
                              </span>
                              <span>
                                {String(groupingValue)}
                              </span>
                              <span className="text-muted-foreground text-sm font-normal">
                                ({row.subRows.length})
                              </span>
                            </span>
                          </div>
                        </td>
                      </tr>
                    );
                  }

                  // --- Normal Row Rendering ---
                  return (
                    <tr
                      key={row.id}
                      className={cn(
                        "hover:bg-muted/50 border-b last:border-0",
                        getRowClassName ? getRowClassName(row.original, row.index) : "",
                        onRowClick ? "cursor-pointer" : ""
                      )}
                      style={{ height: `${virtualRow.size}px` }}
                      onClick={(e) => onRowClick?.(row, e)}
                    >
                      {row.getVisibleCells().map((cell) => {
                        const isPinned = cell.column.getIsPinned();
                        const isGrouped = cell.column.getIsGrouped();

                        const style: React.CSSProperties = {
                          width: cell.column.getSize(),
                        };
                        if (isPinned === "left") {
                          style.position = "sticky";
                          style.left = `${cell.column.getStart("left")}px`;
                          style.zIndex = 20;
                        } else if (isPinned === "right") {
                          style.position = "sticky";
                          style.right = `${cell.column.getAfter("right")}px`;
                          style.zIndex = 20;
                        }

                        return (
                          <td
                            key={cell.id}
                            className={cn(
                              "px-2 py-0 text-sm truncate border-b bg-background",
                              isGrouped ? "bg-muted/20" : ""
                            )}
                            style={style}
                          >
                            {cell.getIsGrouped() ? null : cell.getIsAggregated() ? (
                              flexRender(
                                cell.column.columnDef.aggregatedCell ??
                                  cell.column.columnDef.cell,
                                cell.getContext()
                              )
                            ) : cell.getIsPlaceholder() ? null : (
                              flexRender(cell.column.columnDef.cell, cell.getContext())
                            )}
                          </td>
                        );
                      })}
                    </tr>
                  );
                })
              )}
              {paddingBottom > 0 && (
                <tr>
                  <td style={{ height: `${paddingBottom}px` }} />
                </tr>
              )}
            </tbody>
          </table>
        </DndContext>
      </div>

      <ClientDataTablePagination table={table} />
    </div>
  );
}


