import type { SelectingRow } from '@/components/Table/typing'
import type { User } from '@inject/graphql/fragment-types'
import { useTypedQuery } from '@inject/graphql/graphql'
import { GetUsers } from '@inject/graphql/queries'
import notEmpty from '@inject/shared/utils/notEmpty'
import { useMemo } from 'react'
import useFilterUsers from './useFilterUsers'
import type { AUTH_GROUPS, UserColumn } from './utils'

const activeToBool = (active: { active: boolean; inactive: boolean }) => {
  if (active.active && active.inactive) return undefined
  if (active.active) return true
  if (active.inactive) return false
  return undefined
}

type UserTableProps = {
  onClick: (id: string) => void
  selectedUsers?: string[]
  groups: typeof AUTH_GROUPS
  active: {
    active: boolean
    inactive: boolean
  }
  tags?: string[]
  searchString?: string
  columns: UserColumn[]
} & (
  | {
      onSelectAll?: never
      onDeselectAll?: never
    }
  | {
      onSelectAll: (allIds: string[]) => void
      onDeselectAll: () => void
    }
) &
  (
    | {
        searchString?: string
        filterPredicate?: never
      }
    | {
        searchString?: never
        filterPredicate: (user: User) => boolean
      }
  )

const useUserTable = ({
  onClick,
  selectedUsers,
  groups,
  active,
  tags,
  searchString,
  columns,
  filterPredicate,
  onSelectAll,
  onDeselectAll,
}: UserTableProps) => {
  const [{ data: usersData, fetching: loading }] = useTypedQuery({
    query: GetUsers,
    requestPolicy: 'network-only',
    variables: {
      active: activeToBool(active),
      groups,
      tags: tags && tags.length > 0 ? tags : undefined,
    },
    pause: !active.active && !active.inactive,
  })

  const filteredUsers = useFilterUsers({
    users: usersData?.users?.filter(notEmpty) || [],
    ...(filterPredicate ? { predicate: filterPredicate } : { searchString }),
  })

  const rows: SelectingRow<User>[] = filteredUsers.map(user => ({
    id: user.id,
    value: user,
    onClick: () => onClick(user.id),
    isSelected: selectedUsers?.includes(user.id) || false,
  }))

  // can't do this directly in the props because of a false-positive TS error
  const selectingTableProps = useMemo(
    () =>
      onSelectAll !== undefined
        ? {
            allSelected: selectedUsers?.length === filteredUsers.length,
            onSelectAll: () => onSelectAll(filteredUsers.map(user => user.id)),
            onDeselectAll,
          }
        : {},
    [filteredUsers, onDeselectAll, onSelectAll, selectedUsers?.length]
  )

  return {
    columns,
    rows,
    loading,
    ...selectingTableProps,
  }
}

export default useUserTable
