import {
  Button,
  Dialog,
  DialogBody,
  DialogFooter,
  FormGroup,
  InputGroup,
} from '@blueprintjs/core'
import { css, cx } from '@emotion/css'
import { useTypedMutation } from '@inject/graphql/graphql'
import { AssignUsersByTags } from '@inject/graphql/mutations'
import { dialogBody, maximizedDialog } from '@inject/shared/css/dialog'
import { notify } from '@inject/shared/notification/engine'
import type { FC } from 'react'
import { useCallback, useState } from 'react'
import { AUTH_GROUPS } from '../UserTable/utils'
import useUserTableSelection from '../UserTableSelection/useUserTableSelection'

const body = css`
  display: flex;
  flex-direction: column;
  overflow: auto;
`

interface AssignByTagsProps {
  exerciseId: string
}

const AssignByTags: FC<AssignByTagsProps> = ({ exerciseId }) => {
  const [open, setOpen] = useState(false)
  const [selectedUsers, setSelectedUsers] = useState<string[]>([])
  const [tagPrefix, setTagPrefix] = useState('')

  const reset = useCallback(() => {
    setOpen(false)
    setTagPrefix('')
    setSelectedUsers([])
  }, [])

  const [{ fetching: loading }, assignByTags] =
    useTypedMutation(AssignUsersByTags)
  const handleSubmit = useCallback(() => {
    if (!selectedUsers) return

    assignByTags({
      exerciseId,
      userIds: selectedUsers,
      tagPrefix,
    })
      .then(() => reset())
      .catch(err => notify(err.message, { intent: 'danger' }))
  }, [assignByTags, exerciseId, reset, selectedUsers, tagPrefix])

  const { table } = useUserTableSelection({
    groups: AUTH_GROUPS,
    onCancel: reset,
    onAdd: (ids: string[]) => setSelectedUsers(ids),
    selectedUsers,
    setSelectedUsers,
    /*
     * when tagPrefix changes causing only a subset of users to be displayed,
     * the selected users need not to be reset because if they are not
     * displayed, their tags do not match the prefix and they will be skipped
     * by the mutation
     */
    filterPredicate: tagPrefix
      ? user => user.tags.some(tag => tag.name.startsWith(tagPrefix))
      : undefined,
  })

  return (
    <>
      <Button
        icon='tag'
        text='Assign by tags'
        onClick={() => setOpen(true)}
        active={open}
      />

      <Dialog
        isOpen={open}
        onClose={reset}
        className={maximizedDialog}
        title='Assign users to teams based on tags'
        icon='tag'
      >
        <DialogBody className={cx(dialogBody, body)}>
          <FormGroup
            label='Tag prefix'
            labelInfo='(optional)'
            labelFor='tag-prefix'
            helperText='Users will be assigned to teams based on tags with this prefix'
          >
            <InputGroup
              id='tag-prefix'
              placeholder='example-prefix'
              value={tagPrefix}
              onChange={e => setTagPrefix(e.target.value)}
            />
          </FormGroup>
          {table}
        </DialogBody>
        <DialogFooter
          actions={
            <Button
              onClick={handleSubmit}
              intent='primary'
              disabled={selectedUsers.length === 0}
              title={selectedUsers.length > 0 ? undefined : 'Select some users'}
              loading={loading}
            >
              {`Assign (${selectedUsers.length})`}
            </Button>
          }
        />
      </Dialog>
    </>
  )
}

export default AssignByTags
