import React, { useState, useMemo, useRef } from 'react'
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 useClickOutside from '../../hooks/useClickOutside'
import { Pagination, Header, SimpleRow, DraggableRow, RowDragHandleCell } from './components'
import { UncontrolledTableProps } from './interface'

import * as S from './UncontrolledTable.style'

const UncontrolledTable = (props: UncontrolledTableProps) => {
  const {
    data,
    columns,
    pagination,
    totalPages,
    labels,
    tableClassName,
    sticky,
    draggable,
    buttons,
    configs,
    hideColumns,
  } = props

  const {
    onClick,
    onMouseOver,
    onMouseOut,
    onChangePage,
    onFilterClick,
    onSortClick,
    onDragEnd,
    onColumnVisibilityChange,
  } = props

  const [openFilterDialog, setOpenFilterDialog] = useState('')
  const [sorting, setSorting] = useState<any>([])
  const [filterByColumn, setFilterByColumn] = useState<ColumnFiltersState>([])

  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,
      manualPagination: true,
      debugTable: true,
      debugHeaders: true,
      debugColumns: true,
      getRowId: (row: any) => row.id,
      getCoreRowModel: getCoreRowModel(),
      getSortedRowModel: getSortedRowModel(),
      onSortingChange: setSorting,
      onColumnFiltersChange: setFilterByColumn,
    }

    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 className="Norma__Table">
      <Header
        table={table}
        labels={{
          columns: labels?.columns || 'Colunas',
        }}
        configs={configs}
        menus={buttons}
        hideColumns={hideColumns}
        onColumnVisibilityChange={onColumnVisibilityChange}
      />
      <DndContext
        collisionDetection={closestCenter}
        modifiers={[restrictToVerticalAxis]}
        onDragEnd={handleDragEnd}
        sensors={sensors}
      >
        <S.TableContainer $sticky={sticky?.enabled}>
          <S.Table className={tableClassName || ''}>
            <S.Thead $sticky={sticky?.enabled} $stickyTopP={sticky?.top}>
              {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
                          title={header.column.columnDef.header}
                          $size={header.column.columnDef.width}
                        >
                          {!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
                              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
                              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>
        </S.TableContainer>
      </DndContext>
      {pagination && (
        <Pagination
          pagination={pagination}
          count={totalPages || 0}
          onChangePage={(page: number) => onChangePage?.({ ...pagination, pageIndex: page })}
        />
      )}
    </S.Container>
  )
}

export default UncontrolledTable
