import React, { useState, useMemo, useRef } from 'react';
import * as S from './styles';

import {
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
  ColumnFiltersState,
  TableOptions,
} from '@tanstack/react-table';

import {
  DndContext,
  MouseSensor,
  closestCenter,
  type DragEndEvent,
  type UniqueIdentifier,
  useSensor,
  useSensors,
  TouchSensor,
  KeyboardSensor,
} from '@dnd-kit/core';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';

import { Pagination, Header, SimpleRow, DraggableRow, RowDragHandleCell } from './components';
import { UncontrolledTableProps } from './interface';
import useClickOutside from '../../hooks/useClickOutside';

const UncontrolledTable = (props: UncontrolledTableProps) => {
  const {
    data,
    columns,
    onClick,
    onMouseOver,
    onMouseOut,
    showTotalResults,
    showSettings,
    onChangePage,
    pagination,
    totalPages,
    showClearFields,
    onClearFieldsClick,
    onFilterClick,
    onSortClick,
    customTotalResults,
    labels,
    tableClassName,
    stickyHeader,
    stickyHeaderP,
    draggable,
    onDragEnd,
  } = props;

  const [openFilterDialog, setOpenFilterDialog] = useState('');
  const [sorting, setSorting] = useState<any>([]);
  const [filterByColumn, setFilterByColumn] = useState<ColumnFiltersState>([]);
  const [globalFilters, setGlobalFilters] = useState<any>([]);
  const [orderSmallest, setOrderSmallest] = useState(false);
  const [orderLargest, setOrderLargest] = useState(false);

  const _columns: any[] = useMemo(() => {
    return draggable
      ? [
          {
            id: 'drag',
            header: '',
            cell: ({ row }: { row: any }) => <RowDragHandleCell rowId={row.id}/>,
            disableMenu: true,
          },
          ...columns.map((column) => ({
            ...column,
            disableMenu: true,
          })),
        ]
      : columns;
  }, [columns]);

  const reactTableConfig = useMemo(() => {
    const config: TableOptions<unknown> = {
      data,
      columns: _columns,
      state: {
        sorting: sorting,
        columnFilters: filterByColumn,
        pagination: pagination,
      },
      rowCount: totalPages,
      getCoreRowModel: getCoreRowModel(),
      getSortedRowModel: getSortedRowModel(),
      onSortingChange: setSorting,
      onColumnFiltersChange: setFilterByColumn,
      manualPagination: true,
      getRowId: (row: any) => row.id,
      debugTable: true,
      debugHeaders: true,
      debugColumns: true,
    };

    return config;
  }, [data, sorting, filterByColumn, _columns, pagination]);

  const table = useReactTable(reactTableConfig);
  const filterRef = useRef<HTMLDivElement>(null);

  useClickOutside(filterRef, () => setOpenFilterDialog(''));

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;


    if (active && over && active.id !== over.id && onDragEnd) {
      const oldIndex = dataIds.indexOf(active.id);
      const newIndex = dataIds.indexOf(over.id);

      const _data = arrayMove(data, oldIndex, newIndex);
      onDragEnd(_data);
    }
  };

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

  const dataIds = useMemo<UniqueIdentifier[]>(
    () => data?.map((item: { id: UniqueIdentifier }) => item.id) || [],
    [data],
  );

  return (
    <S.Container>
      <Header
        table={table}
        globalFilters={globalFilters}
        orderSmallest={orderSmallest}
        orderLargest={orderLargest}
        showTotalResults={showTotalResults}
        showSettings={showSettings}
        setGlobalFilters={setGlobalFilters}
        setOrderLargest={setOrderLargest}
        setOrderSmallest={setOrderSmallest}
        showClearFiels={showClearFields}
        customTotalResults={customTotalResults}
        clearLabel={labels?.clearFilter}
        onClearFieldsClick={() => onClearFieldsClick && onClearFieldsClick()}
        customIcons={props.customIcons}
        hideColumns={props.hideColumns}
        onColumnVisibilityChange={props.onColumnVisibilityChange}
      />
      <DndContext
        collisionDetection={closestCenter}
        modifiers={[restrictToVerticalAxis]}
        onDragEnd={handleDragEnd}
        sensors={sensors}
      >
        <S.Table className={tableClassName || ''}>
          <S.Thead $sticky={stickyHeader} $stickyTopP={stickyHeaderP}>
            {table.getHeaderGroups().map((headerGroup: any) => (
              <S.TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header: any) => (
                  <S.Th key={header.id}>
                    <S.ColumnContent
                      onClick={() => {
                        if (!header?.column?.columnDef?.disableMenu)
                          setOpenFilterDialog(header.column.columnDef.accessorKey);
                      }}
                    >
                      <S.TextColumn>
                        {!header.isPlaceholder && flexRender(header.column.columnDef.header, header.getContext())}
                      </S.TextColumn>
                      {!header?.column?.columnDef?.disableMenu && (
                        <S.IconFilterDialog>
                          <svg fill="#666" focusable="false" aria-hidden="true" viewBox="0 0 24 24">
                            <path d="m7 10 5 5 5-5z" />
                          </svg>
                        </S.IconFilterDialog>
                      )}
                    </S.ColumnContent>
                    {openFilterDialog === header.column.columnDef.accessorKey && (
                      <S.FilterDialog ref={filterRef}>
                        <S.ListFilterDialog>
                          <S.OptionFilterDialog
                            style={{
                              background: orderSmallest ? 'rgba(0, 0, 0, 0.04)' : '',
                            }}
                            onClick={() => {
                              onSortClick && onSortClick(header.column.columnDef.accessorKey, 'asc');
                              setOpenFilterDialog('');
                            }}
                          >
                            <div className="icon">
                              <svg
                                fill="#666"
                                stroke="currentColor"
                                strokeWidth="1.5"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                                aria-hidden="true"
                                width="20"
                                height="20"
                              >
                                <path
                                  strokeLinecap="round"
                                  strokeLinejoin="round"
                                  d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
                                />
                              </svg>
                            </div>
                            <p>{labels?.orderAsc || 'Menor primeiro'}</p>
                          </S.OptionFilterDialog>
                          <S.OptionFilterDialog
                            style={{
                              background: orderLargest ? 'rgba(0, 0, 0, 0.04)' : '',
                            }}
                            onClick={() => {
                              onSortClick && onSortClick(header.column.columnDef.accessorKey, 'desc');
                              setOpenFilterDialog('');
                            }}
                          >
                            <div className="icon rotate">
                              <svg
                                fill="#666"
                                stroke="currentColor"
                                strokeWidth="1.5"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                                aria-hidden="true"
                                width="20"
                                height="20"
                              >
                                <path
                                  strokeLinecap="round"
                                  strokeLinejoin="round"
                                  d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
                                ></path>
                              </svg>
                            </div>
                            <p>{labels?.orderDesc || 'Maior primeiro'}</p>
                          </S.OptionFilterDialog>
                          {!header?.column?.columnDef?.nofilter && (
                            <S.OptionFilterDialog
                              onClick={() => {
                                onFilterClick && onFilterClick(header.column.columnDef.accessorKey);
                                setOpenFilterDialog('');
                              }}
                            >
                              <div className="icon">
                                <svg
                                  fill="none"
                                  stroke="currentColor"
                                  strokeWidth="1.5"
                                  viewBox="0 0 24 24"
                                  xmlns="http://www.w3.org/2000/svg"
                                  aria-hidden="true"
                                  width="16"
                                  height="16"
                                >
                                  <path
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                    d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z"
                                  ></path>
                                </svg>
                              </div>
                              <p>{labels?.filter || 'Filtrar por'}</p>
                            </S.OptionFilterDialog>
                          )}
                        </S.ListFilterDialog>
                      </S.FilterDialog>
                    )}
                  </S.Th>
                ))}
              </S.TableRow>
            ))}
          </S.Thead>
          <tbody>
            <SortableContext items={dataIds} strategy={verticalListSortingStrategy}>
              {table.getRowModel().rows.map((row: any) => {
                return draggable ? (
                  <DraggableRow
                    key={row.id}
                    row={row}
                    onClick={onClick}
                    onMouseOver={onMouseOver}
                    onMouseOut={onMouseOut}
                  />
                ) : (
                  <SimpleRow
                    key={row.id}
                    row={row}
                    onClick={onClick}
                    onMouseOver={onMouseOver}
                    onMouseOut={onMouseOut}
                  />
                );
              })}
            </SortableContext>
          </tbody>
        </S.Table>
      </DndContext>
      {pagination && (
        <Pagination
          pagination={pagination}
          count={totalPages}
          onChangePage={(page: number) => onChangePage({ ...pagination, pageIndex: page })}
        />
      )}
    </S.Container>
  );
};

export default UncontrolledTable;
