import { ButtonGroup, DataTableColumnHeader } from "@/components";
import { Badge, Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/ui";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/ui/table";
import {
  DndContext,
  DragEndEvent,
  DragOverlay,
  DragStartEvent,
  DropAnimation,
  KeyboardSensor,
  MeasuringStrategy,
  MouseSensor,
  PointerSensor,
  TouchSensor,
  UniqueIdentifier,
  closestCenter,
  defaultDropAnimation,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import {
  ColumnDef,
  InitialTableState,
  Row,
  RowData,
  RowSelectionState,
  VisibilityState,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { useMemo, useState } from "react";
import { createPortal } from "react-dom";
import { FieldValues, UseFieldArrayReturn } from "react-hook-form";
import { AppendBlockRowButton } from "./AppendBlockRowButton";
import { AppendCatalogArticleRowButton } from "./AppendCatalogArticleRowButton";
import { AppendEmptyRowButton } from "./AppendEmptyRowButton";
import { QuoteItemsSortableDataTableToolbar } from "./QuoteItemsSortableDataTableToolbar";
import { QuoteItemsSortableTableRow } from "./QuoteItemsSortableTableRow";

export type RowIdData = { [x: string]: any };

declare module "@tanstack/react-table" {
  interface TableMeta<TData extends RowData> {
    insertItem: (rowIndex: number, data?: unknown) => void;
    appendItem: (data?: unknown) => void;
    pickCatalogArticle?: () => void;
    pickBlock?: () => void;
    duplicateItems: (rowIndex?: number) => void;
    deleteItems: (rowIndex?: number | number[]) => void;
    updateItem: (
      rowIndex: number,
      rowData: TData & RowIdData,
      fieldName: string,
      value: unknown
    ) => void;
  }
}

export interface QuoteItemsSortableProps {
  id: UniqueIdentifier;
}

export type QuoteItemsSortableDataTableProps<
  TData extends RowData & RowIdData,
  TValue = unknown
> = {
  columns: ColumnDef<TData, TValue>[];
  data: TData[];
  defaultValues: Readonly<{ [x: string]: any }> | undefined;
  initialState?: InitialTableState;
  actions: Omit<UseFieldArrayReturn<FieldValues, "items">, "fields"> & {
    pickCatalogArticle?: () => void;
    pickBlock?: () => void;
  };
};

const measuringConfig = {
  droppable: {
    strategy: MeasuringStrategy.Always,
  },
};

const dropAnimationConfig: DropAnimation = {
  keyframes({ transform }) {
    return [
      { opacity: 1, transform: CSS.Transform.toString(transform.initial) },
      {
        opacity: 0,
        transform: CSS.Transform.toString({
          ...transform.final,
          x: transform.final.x + 5,
          y: transform.final.y + 5,
        }),
      },
    ];
  },
  easing: "ease-out",
  sideEffects({ active }) {
    active.node.animate([{ opacity: 0 }, { opacity: 1 }], {
      duration: defaultDropAnimation.duration,
      easing: defaultDropAnimation.easing,
    });
  },
};

export function QuoteItemsSortableDataTable<TData extends RowData & RowIdData, TValue = unknown>({
  columns,
  data,
  defaultValues,
  initialState,
  actions,
}: QuoteItemsSortableDataTableProps<TData, TValue>) {
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
  const [activeId, setActiveId] = useState<UniqueIdentifier | null>();

  const [columnVisibility, _setColumnVisibility] = useState<VisibilityState>(
    initialState?.columnVisibility || {}
  );

  const sorteableRowIds = useMemo(() => data.map((item) => item.id), [data]);

  const table = useReactTable<TData>({
    data,
    columns,
    enableColumnResizing: false,
    columnResizeMode: "onChange",
    //defaultColumn,

    autoResetAll: false, // <-- añadido nuevo
    initialState,
    state: {
      rowSelection,
      columnVisibility,
    },
    enableRowSelection: true,
    enableMultiRowSelection: true,
    enableSorting: false,
    enableHiding: true,

    onRowSelectionChange: setRowSelection,
    getCoreRowModel: getCoreRowModel(),
    getRowId: (originalRow) => originalRow?.id,

    debugTable: false,
    debugHeaders: false,
    debugColumns: false,

    defaultColumn: {
      minSize: 0, //starting column size
      size: Number.MAX_SAFE_INTEGER, //enforced during column resizing
      maxSize: Number.MAX_SAFE_INTEGER, //enforced during column resizing
    },

    meta: {
      insertItem: (rowIndex: number, data?: unknown) => {
        actions.insert(rowIndex, data || defaultValues?.items[0], { shouldFocus: true });
      },
      appendItem: (data?: unknown) => {
        actions.append(data || defaultValues?.items[0], { shouldFocus: true });
      },
      pickCatalogArticle: () => {
        if (actions.pickCatalogArticle) {
          actions?.pickCatalogArticle();
        }
      },
      pickBlock: () => {
        if (actions.pickBlock) {
          actions?.pickBlock();
        }
      },
      duplicateItems: (rowIndex?: number) => {
        if (rowIndex != undefined) {
          const originalData = table.getRowModel().rows[rowIndex].original;
          actions.insert(rowIndex + 1, originalData, { shouldFocus: true });
        } else if (table.getSelectedRowModel().rows.length) {
          const lastIndex =
            table.getSelectedRowModel().rows[table.getSelectedRowModel().rows.length - 1].index;

          const data = table
            .getSelectedRowModel()
            .rows.map((row: Row<any>) => ({ ...row.original, id: undefined }));

          if (table.getRowModel().rows.length < lastIndex + 1) {
            actions.append(data);
          } else {
            actions.insert(lastIndex + 1, data, { shouldFocus: true });
          }
          table.resetRowSelection();
        }
      },
      deleteItems: (rowIndex?: number | number[]) => {
        if (rowIndex != undefined) {
          actions.remove(rowIndex);
        } else if (table.getSelectedRowModel().rows.length > 0) {
          let start = table.getSelectedRowModel().rows.length - 1;
          for (; start >= 0; start--) {
            const oldIndex = sorteableRowIds.indexOf(
              String(table.getSelectedRowModel().rows[start].id)
            );
            actions.remove(oldIndex);
            sorteableRowIds.splice(oldIndex, 1);
          }

          /*table.getSelectedRowModel().rows.forEach((row) => {
          });*/
          table.resetRowSelection();
        } else {
          actions.remove();
        }
      },
      updateItem: (rowIndex: number, rowData: any, fieldName: string, value: unknown) => {
        // Skip page index reset until after next rerender
        // skipAutoResetPageIndex();
        actions.update(rowIndex, { ...rowData, [`${fieldName}`]: value });
      },
    },
  });

  const sensors = useSensors(
    useSensor(MouseSensor, {}),
    useSensor(TouchSensor, {}),
    useSensor(KeyboardSensor, {}),
    useSensor(PointerSensor, {})
  );

  function handleDragEnd(event: DragEndEvent) {
    let activeId = event.active.id;
    let overId = event.over?.id;

    if (overId !== undefined && activeId !== overId) {
      let newIndex = sorteableRowIds.indexOf(String(overId));

      if (table.getSelectedRowModel().rows.length > 1) {
        table.getSelectedRowModel().rows.forEach((row, index) => {
          const oldIndex = sorteableRowIds.indexOf(String(row.id));

          if (index > 0) {
            activeId = row.id;
            newIndex = sorteableRowIds.indexOf(String(overId));
            if (newIndex < oldIndex) {
              newIndex = newIndex + 1;
            }
          }

          actions.move(oldIndex, newIndex);
          sorteableRowIds.splice(newIndex, 0, sorteableRowIds.splice(oldIndex, 1)[0]);

          overId = row.id;
        });
      } else {
        const oldIndex = sorteableRowIds.indexOf(String(activeId));
        actions.move(oldIndex, newIndex);
      }
    }

    setActiveId(null);
  }

  function handleDragStart({ active }: DragStartEvent) {
    if (!table.getSelectedRowModel().rowsById[active.id]) {
      table.resetRowSelection();
    }

    setActiveId(active.id);
  }

  function handleDragCancel() {
    setActiveId(null);
  }

  function filterItems(items: string[] | Row<unknown>[]) {
    if (!activeId) {
      return items;
    }

    return items.filter((idOrRow) => {
      const id = typeof idOrRow === "string" ? idOrRow : idOrRow.id;
      return id === activeId || !table.getSelectedRowModel().rowsById[id];
    });
  }

  return (
    <DndContext
      measuring={measuringConfig}
      sensors={sensors}
      onDragEnd={handleDragEnd}
      onDragStart={handleDragStart}
      onDragCancel={handleDragCancel}
      collisionDetection={closestCenter}
    >
      <Card>
        <CardHeader className='sticky z-10 top-16 bg-card/90'>
          <CardTitle>
            <QuoteItemsSortableDataTableToolbar table={table} />
          </CardTitle>
        </CardHeader>
        <CardContent>
          <Table className='table-fixed'>
            <TableHeader className='sticky top-0 z-10 bg-background'>
              {table.getHeaderGroups().map((headerGroup) => (
                <TableRow key={headerGroup.id} className='hover:bg-transparent'>
                  {headerGroup.headers.map((header) => {
                    return (
                      <TableHead
                        key={header.id}
                        className='px-2 py-1'
                        style={{
                          width:
                            header.getSize() === Number.MAX_SAFE_INTEGER
                              ? "auto"
                              : header.getSize(),
                        }}
                      >
                        {header.isPlaceholder ? null : (
                          <DataTableColumnHeader table={table} header={header} />
                        )}
                      </TableHead>
                    );
                  })}
                </TableRow>
              ))}
            </TableHeader>
            <TableBody>
              <SortableContext
                items={filterItems(sorteableRowIds)}
                strategy={verticalListSortingStrategy}
              >
                {filterItems(table.getRowModel().rows).map((row) => (
                  <QuoteItemsSortableTableRow key={(row as Row<any>).id} id={(row as Row<any>).id}>
                    {(row as Row<any>).getVisibleCells().map((cell) => (
                      <TableCell
                        key={cell.id}
                        className='px-2 py-2 align-top'
                        style={{
                          width:
                            cell.column.getSize() === Number.MAX_SAFE_INTEGER
                              ? "auto"
                              : cell.column.getSize(),
                        }}
                      >
                        {flexRender(cell.column.columnDef.cell, cell.getContext())}
                      </TableCell>
                    ))}
                  </QuoteItemsSortableTableRow>
                ))}
              </SortableContext>
            </TableBody>
          </Table>

          {createPortal(
            <DragOverlay dropAnimation={dropAnimationConfig} className={"z-40 opacity-100"}>
              {activeId && (
                <div className='relative flex flex-wrap'>
                  {table.getSelectedRowModel().rows.length ? (
                    <Badge
                      variant='destructive'
                      className='absolute z-50 flex items-center justify-center w-2 h-2 p-3 rounded-full top left -left-2 -top-2'
                    >
                      {table.getSelectedRowModel().rows.length}
                    </Badge>
                  ) : null}
                  <div className='absolute z-40 bg-white border rounded shadow opacity-100 top left hover:bg-white border-muted-foreground/50'>
                    <Table>
                      <TableBody>
                        {table.getRowModel().rows.map(
                          (row) =>
                            row.id === activeId && (
                              <TableRow key={row.id} id={row.id}>
                                {row.getVisibleCells().map((cell) => (
                                  <TableCell
                                    className='p-1 align-top'
                                    key={cell.id}
                                    style={{ width: cell.column.getSize() }}
                                  >
                                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                  </TableCell>
                                ))}
                              </TableRow>
                            )
                        )}
                      </TableBody>
                    </Table>
                  </div>

                  {table.getSelectedRowModel().rows.length > 1 && (
                    <div className='absolute z-30 transform -translate-x-1 translate-y-1 bg-white border rounded shadow opacity-100 hover:bg-white border-muted-foreground/50 top left rotate-1'>
                      <Table>
                        <TableBody>
                          {table.getRowModel().rows.map(
                            (row) =>
                              row.id === activeId && (
                                <TableRow key={row.id} id={row.id}>
                                  {row.getVisibleCells().map((cell) => (
                                    <TableCell
                                      className='p-1 align-top'
                                      key={cell.id}
                                      style={{ width: cell.column.getSize() }}
                                    >
                                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                    </TableCell>
                                  ))}
                                </TableRow>
                              )
                          )}
                        </TableBody>
                      </Table>
                    </div>
                  )}

                  {table.getSelectedRowModel().rows.length > 2 && (
                    <div className='absolute z-20 transform translate-x-1 -translate-y-1 bg-white border rounded shadow opacity-100 hover:bg-white border-muted-foreground/50 top left -rotate-1'>
                      <Table>
                        <TableBody>
                          {table.getRowModel().rows.map(
                            (row) =>
                              row.id === activeId && (
                                <TableRow key={row.id} id={row.id}>
                                  {row.getVisibleCells().map((cell) => (
                                    <TableCell
                                      className='p-1 align-top'
                                      key={cell.id}
                                      style={{ width: cell.column.getSize() }}
                                    >
                                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                    </TableCell>
                                  ))}
                                </TableRow>
                              )
                          )}
                        </TableBody>
                      </Table>
                    </div>
                  )}

                  {table.getSelectedRowModel().rows.length > 3 && (
                    <div className='absolute z-10 transform translate-x-2 -translate-y-2 bg-white border rounded shadow opacity-100 hover:bg-white border-muted-foreground/50 top left rotate-2'>
                      <Table>
                        <TableBody>
                          {table.getRowModel().rows.map(
                            (row) =>
                              row.id === activeId && (
                                <TableRow key={row.id} id={row.id}>
                                  {row.getVisibleCells().map((cell) => (
                                    <TableCell
                                      className='p-1 align-top'
                                      key={cell.id}
                                      style={{ width: cell.column.getSize() }}
                                    >
                                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                    </TableCell>
                                  ))}
                                </TableRow>
                              )
                          )}
                        </TableBody>
                      </Table>
                    </div>
                  )}
                </div>
              )}
            </DragOverlay>,
            document.body
          )}
        </CardContent>
        <CardFooter>
          <ButtonGroup>
            <AppendEmptyRowButton onClick={() => table.options.meta?.appendItem()} />
            <AppendCatalogArticleRowButton
              onClick={() => {
                if (table.options.meta && table.options.meta.pickCatalogArticle) {
                  table.options.meta?.pickCatalogArticle();
                }
              }}
            />
            <AppendBlockRowButton
              onClick={() => {
                if (table.options.meta && table.options.meta.pickBlock) {
                  table.options.meta?.pickBlock();
                }
              }}
            />
          </ButtonGroup>
        </CardFooter>
      </Card>
    </DndContext>
  );
}
