import {
  Button,
  Classes,
  Dialog,
  DialogBody,
  DialogFooter,
  FormGroup,
  InputGroup,
  Label,
  MenuItem,
} from '@blueprintjs/core'
import { MultiSelect, Select } from '@blueprintjs/select'
import { css } from '@emotion/css'
import useApolloClient from '@inject/graphql/client/useApolloClient'
import type { Tag } from '@inject/graphql/fragments/Tag.generated'
import { useCreateUser } from '@inject/graphql/mutations/CreateUser.generated'
import {
  GetTagsDocument,
  useGetTags,
} from '@inject/graphql/queries/GetTags.generated'
import { GetUsersDocument } from '@inject/graphql/queries/GetUsers.generated'
import type { AuthGroup } from '@inject/graphql/types'
import { dialog } from '@inject/shared/css/dialog'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import notEmpty from '@inject/shared/utils/notEmpty'
import { useCallback, useState } from 'react'
import { AUTH_GROUPS } from '../UserTable/utils'

const label = css`
  width: 100%;
`

const UserCreator = () => {
  const [open, setOpen] = useState<boolean>(false)
  const { notify } = useNotifyContext()
  const client = useApolloClient()
  const [createUser, { loading }] = useCreateUser()

  const { data } = useGetTags()
  const availableTags = data?.tags?.filter(notEmpty) || []

  const [email, setEmail] = useState<string>()
  const [firstName, setFirstName] = useState<string>()
  const [lastName, setLastName] = useState<string>()
  const [tagsQuery, setTagsQuery] = useState<string>()
  const [tags, setTags] = useState<Tag[]>()
  const [group, setGroup] = useState<AuthGroup>()

  const handleSubmit = useCallback(() => {
    if (!email || !group) return

    createUser({
      variables: {
        email,
        firstName: firstName || null,
        lastName: lastName || null,
        tags: tags?.map(tag => tag.name) || [],
        group,
      },
      onCompleted: () => {
        setOpen(false)
        client.refetchQueries({
          include: [GetUsersDocument, GetTagsDocument],
        })
        setEmail(undefined)
        setFirstName(undefined)
        setLastName(undefined)
        setTags(undefined)
        setGroup(undefined)
      },
      onError: err => {
        notify(err.message, {
          intent: 'danger',
        })
      },
    })
  }, [client, createUser, email, firstName, group, lastName, notify, tags])

  return (
    <>
      <Button
        minimal
        active={open}
        onClick={() => {
          setOpen(true)
        }}
        fill
        alignText='left'
        icon='add'
      >
        Create a user
      </Button>

      <Dialog
        className={dialog}
        title='Create a user'
        isOpen={open}
        onClose={() => setOpen(false)}
        icon='add'
      >
        <DialogBody>
          <Label className={label}>
            Email
            <InputGroup
              leftIcon='envelope'
              placeholder='john.doe@example.com'
              value={email}
              onChange={e => setEmail(e.target.value)}
            />
          </Label>
          <Label className={label}>
            First name <span className={Classes.TEXT_MUTED}>(optional)</span>
            <InputGroup
              placeholder='John'
              value={firstName}
              onChange={e => setFirstName(e.target.value)}
            />
          </Label>
          <Label className={label}>
            Last name <span className={Classes.TEXT_MUTED}>(optional)</span>
            <InputGroup
              placeholder='Doe'
              value={lastName}
              onChange={e => setLastName(e.target.value)}
            />
          </Label>
          <Label className={label}>
            Group
            <Select<AuthGroup>
              fill
              onItemSelect={group => setGroup(group)}
              items={AUTH_GROUPS}
              popoverProps={{ minimal: true }}
              itemRenderer={(item, { handleClick }) => (
                <MenuItem
                  onClick={handleClick}
                  text={item}
                  active={item === group}
                />
              )}
              filterable={false}
            >
              <Button
                alignText='left'
                fill
                rightIcon='double-caret-vertical'
                text={group || 'Select a group'}
              />
            </Select>
          </Label>
          {/* using Label directly messes up the MultiSelect */}
          <FormGroup
            fill
            label={
              <>
                Tags <span className={Classes.TEXT_MUTED}>(optional)</span>
              </>
            }
            labelFor='create-user-tags'
          >
            <MultiSelect<Tag>
              tagInputProps={{ inputProps: { id: 'create-user-tags' } }}
              query={tagsQuery}
              onQueryChange={setTagsQuery}
              items={
                tagsQuery
                  ? availableTags.filter(tag => tag.name.includes(tagsQuery))
                  : availableTags
              }
              itemRenderer={(item, { handleClick }) => (
                <MenuItem
                  key={item.id}
                  text={item.name}
                  roleStructure='listoption'
                  shouldDismissPopover={false}
                  onClick={handleClick}
                  selected={tags?.includes(item)}
                  active={tags?.includes(item)}
                />
              )}
              onItemSelect={(item: Tag) =>
                setTags(prev =>
                  prev?.includes(item)
                    ? prev.filter(tag => tag.id !== item.id)
                    : [...(prev || []), item]
                )
              }
              onRemove={item =>
                setTags(prev => prev?.filter(tag => tag.id !== item.id))
              }
              selectedItems={tags || []}
              tagRenderer={item => item.name}
              popoverProps={{
                minimal: true,
              }}
            />
          </FormGroup>
        </DialogBody>
        <DialogFooter
          actions={
            <Button
              onClick={handleSubmit}
              intent='primary'
              disabled={!email || !group}
              title={email && group ? undefined : 'Fill in all required fields'}
              loading={loading}
            >
              Submit
            </Button>
          }
        />
      </Dialog>
    </>
  )
}

export default UserCreator
