import { expandToBackendURL } from '@plone/volto/helpers/Url/Url';
import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
import React from 'react';
import {
  Button,
  Table,
  TableBody,
  TableCell,
  TableHeader,
  TableHeaderCell,
  TableRow,
  Input,
} from 'semantic-ui-react';

function Filter({ column }) {
  const columnFilterValue = column.getFilterValue();
  const { filterVariant } = column.columnDef.meta ?? {};
  const handleRangeNumberChangeMin = React.useCallback(
    (value) => {
      column.setFilterValue((old) => [value, old?.[1]]);
    },
    [column],
  );
  const handleRangeNumberChangeMax = React.useCallback(
    (value) => column.setFilterValue((old) => [old?.[0], value]),
    [column],
  );

  const handleTextChange = React.useCallback(
    (value) => column.setFilterValue(value),
    [column],
  );

  return filterVariant === 'range' ? (
    <div>
      <div className="flex space-x-2">
        {/* See faceted column filters example for min max values functionality */}
        <DebouncedInput
          type="number"
          value={columnFilterValue?.[0] ?? ''}
          onChange={handleRangeNumberChangeMin}
          placeholder={`Min`}
          className="w-24 border shadow rounded"
        />
        <DebouncedInput
          type="number"
          value={columnFilterValue?.[1] ?? ''}
          onChange={handleRangeNumberChangeMax}
          placeholder={`Max`}
          className="w-24 border shadow rounded"
        />
      </div>
      <div className="h-1" />
    </div>
  ) : filterVariant === 'select' ? (
    <select
      onBlur={(e) => column.setFilterValue(e.target.value)}
      onChange={(e) => column.setFilterValue(e.target.value)}
      value={columnFilterValue?.toString()}
    >
      {/* See faceted column filters example for dynamic select options */}
      <option value="">All</option>
      <option value="complicated">complicated</option>
      <option value="relationship">relationship</option>
      <option value="single">single</option>
    </select>
  ) : (
    <DebouncedInput
      className="w-36 border shadow rounded"
      onChange={handleTextChange}
      placeholder={`Search...`}
      type="text"
      value={columnFilterValue ?? ''}
    />
    // See faceted column filters example for datalist search suggestions
  );
}

// A typical debounced input react component
function DebouncedInput({
  value: initialValue,
  onChange,
  debounce = 500,
  className,
  ...props
}) {
  const [value, setValue] = React.useState(initialValue);

  React.useEffect(() => {
    setValue(initialValue);
  }, [initialValue]);

  React.useEffect(() => {
    const timeout = setTimeout(() => {
      onChange(value);
    }, debounce);

    return () => clearTimeout(timeout);
  }, [value, debounce, onChange]);

  return (
    <Input
      {...props}
      value={value}
      onChange={(_, data) => setValue(data.value)}
    />
  );
}

export function BrokenLinksComponent({ reactTable }) {
  const { createColumnHelper } = reactTable;

  const [results, setResults] = React.useState({});

  React.useEffect(() => {
    const url = expandToBackendURL('/@broken_links');
    let isMounted = true;
    async function handler() {
      try {
        const response = await fetch(url, {
          method: 'GET',
          headers: {
            Accept: 'application/json',
          },
        });
        const results = await response.json();
        const data = Array.from(Object.values(results.broken_links));
        if (isMounted) setResults(data);
      } catch {
        // eslint-disable-next-line no-console
        console.error('Error in fetching broken links');
      }
    }
    handler();
    return () => (isMounted = false);
  }, []);

  const columnHelper = createColumnHelper();
  const columns = React.useMemo(
    () => [
      columnHelper.accessor('url', {
        header: () => 'URL',
        cell: (info) => <a href={info.getValue()}>{info.getValue()}</a>,
        filterFn: 'includesString',
      }),
      columnHelper.accessor('status', {
        header: () => 'Status',
        filterFn: 'includesString',
      }),
      columnHelper.accessor('date', {
        header: () => 'Last checked',
        filterFn: 'includesString',
      }),

      columnHelper.accessor('object_url', {
        header: () => 'Reference from',
        cell: (info) => <a href={info.getValue()}>{info.getValue()}</a>,
        filterFn: 'includesString',
      }),
    ],
    [columnHelper],
  );

  return (
    <FilteredTable data={results} columns={columns} reactTable={reactTable} />
  );
}

function FilteredTable({ reactTable, data, columns }) {
  const {
    useReactTable,
    getPaginationRowModel,
    getCoreRowModel,
    flexRender,
    getFilteredRowModel,
    getSortedRowModel,
  } = reactTable;

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
  });

  return (
    <div className="broken-links-table ui container">
      <Table>
        <TableHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <TableHeaderCell key={header.id} className={header.id}>
                  {header.isPlaceholder ? null : (
                    <>
                      <div
                        tabIndex="-1"
                        role="button"
                        onKeyDown={header.column.getToggleSortingHandler()}
                        {...{
                          className: header.column.getCanSort()
                            ? 'cursor-pointer select-none'
                            : '',
                          onClick: header.column.getToggleSortingHandler(),
                        }}
                      >
                        {flexRender(
                          header.column.columnDef.header,
                          header.getContext(),
                        )}
                        {{
                          asc: ' 🔼',
                          desc: ' 🔽',
                        }[header.column.getIsSorted()] ?? null}
                      </div>
                      {header.column.getCanFilter() ? (
                        <div>
                          <Filter column={header.column} />
                        </div>
                      ) : null}
                    </>
                  )}
                </TableHeaderCell>
              ))}
            </TableRow>
          ))}
        </TableHeader>
        <TableBody>
          {table.getRowModel().rows.map((row) => {
            return (
              <TableRow key={row.id}>
                {row.getVisibleCells().map((cell) => (
                  <TableCell key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </TableCell>
                ))}
              </TableRow>
            );
          })}
        </TableBody>
      </Table>
      <div className="pagination">
        <Button
          onClick={() => table.firstPage()}
          disabled={!table.getCanPreviousPage()}
        >
          {'<<'}
        </Button>
        <Button
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
        >
          {'<'}
        </Button>
        <Button
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
        >
          {'>'}
        </Button>
        <Button
          onClick={() => table.lastPage()}
          disabled={!table.getCanNextPage()}
        >
          {'>>'}
        </Button>
        <select
          value={table.getState().pagination.pageSize}
          onChange={(e) => {
            table.setPageSize(Number(e.target.value));
          }}
          onBlur={(e) => {
            table.setPageSize(Number(e.target.value));
          }}
        >
          {[10, 20, 30, 40, 50].map((pageSize) => (
            <option key={pageSize} value={pageSize}>
              {pageSize}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
}

export default injectLazyLibs(['reactTable'])(BrokenLinksComponent);
