import { Icon, MenuItem, Tooltip } from '@blueprintjs/core'
import type { ItemRenderer } from '@blueprintjs/select'
import { MultiSelect } from '@blueprintjs/select'
import type { EmailParticipant } from '@inject/graphql/fragments/EmailParticipant.generated'
import { useValidateEmailAddressLazyQuery } from '@inject/graphql/queries/ValidateEmailAddress.generated'
import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext'
import type { Dispatch, FC, MouseEventHandler, SetStateAction } from 'react'
import { useCallback, useMemo } from 'react'
import type { ExtendedItemRenderer } from '../typing'

interface EmailContactSelectorProps {
  emailContacts: EmailParticipant[]
  selectedContacts: string[]
  setSelectedContacts: Dispatch<SetStateAction<string[]>>
  inInstructor: boolean
  exerciseId: string
  placeholder?: string
  senderAddress: string
}

const EmailContactSelector: FC<EmailContactSelectorProps> = ({
  placeholder,
  emailContacts,
  selectedContacts,
  setSelectedContacts,
  inInstructor,
  exerciseId,
  senderAddress,
}) => {
  const suggestedItems = useMemo(
    () =>
      emailContacts
        .map(contact => contact.address)
        .filter(address => address !== senderAddress),
    [emailContacts, senderAddress]
  )
  const selectedItems = useMemo(
    () => selectedContacts.filter(contact => contact !== senderAddress),
    [selectedContacts, senderAddress]
  )

  const [validateEmailAddress] = useValidateEmailAddressLazyQuery()

  const { notify } = useNotifyContext()

  const itemRenderer: ExtendedItemRenderer<string> = useCallback(
    (i, { handleClick, handleFocus, modifiers, hasTooltip }) => (
      <MenuItem
        active={modifiers.active}
        disabled={modifiers.disabled}
        onClick={handleClick}
        onFocus={handleFocus}
        roleStructure='listoption'
        selected={selectedContacts.includes(i)}
        shouldDismissPopover={false}
        text={
          <div>
            <Icon
              icon='small-info-sign'
              style={{ visibility: hasTooltip ? undefined : 'hidden' }}
            />
            {i}
          </div>
        }
        key={i}
      />
    ),
    [selectedContacts]
  )

  const instructorItemRenderer: ItemRenderer<string> = useCallback(
    (i, props) => {
      const tooltipContent = emailContacts.find(
        contact => contact.address === i
      )?.definitionAddress?.description

      return tooltipContent ? (
        <Tooltip content={tooltipContent} targetTagName='div' key={i}>
          {itemRenderer(i, { ...props, hasTooltip: true })}
        </Tooltip>
      ) : (
        itemRenderer(i, props)
      )
    },
    [emailContacts, itemRenderer]
  )

  const itemDisabled = useCallback(
    (i: string) => i === senderAddress,
    [senderAddress]
  )
  const onItemSelect = useCallback(
    async (i: string) => {
      const { data: validateData } = await validateEmailAddress({
        variables: {
          exerciseId,
          address: i,
        },
      })
      if (!validateData?.validateEmailAddress) {
        notify('Invalid email address', { intent: 'danger' })
        return
      }

      setSelectedContacts(prev => {
        if (prev.includes(i)) {
          return prev.filter(x => x !== i)
        }
        return [...prev, i]
      })
    },
    [exerciseId, notify, setSelectedContacts, validateEmailAddress]
  )
  const onRemove = useCallback(
    (i: string) => setSelectedContacts(prev => prev.filter(x => x !== i)),
    [setSelectedContacts]
  )

  const createNewItemFromQuery: (query: string) => string | string[] =
    useCallback((query: string) => query, [])
  const createNewItemRenderer: (
    query: string,
    active: boolean,
    handleClick: MouseEventHandler<HTMLElement>
  ) => undefined | JSX.Element = useCallback(
    (
      query: string,
      active: boolean,
      handleClick: MouseEventHandler<HTMLElement>
    ) => (
      <MenuItem
        active={active}
        onClick={handleClick}
        roleStructure='listoption'
        shouldDismissPopover={false}
        text={query}
      />
    ),
    []
  )

  return (
    <MultiSelect<string>
      placeholder={placeholder}
      itemRenderer={inInstructor ? instructorItemRenderer : itemRenderer}
      items={suggestedItems}
      itemDisabled={itemDisabled}
      itemPredicate={(query, item) => item.startsWith(query)}
      onItemSelect={onItemSelect}
      onRemove={onRemove}
      popoverProps={{
        minimal: true,
      }}
      resetOnSelect
      selectedItems={selectedItems}
      tagRenderer={i => i}
      popoverContentProps={{
        style: { maxHeight: '50vh', overflowY: 'auto', overflowX: 'hidden' },
      }}
      createNewItemFromQuery={createNewItemFromQuery}
      createNewItemRenderer={createNewItemRenderer}
    />
  )
}

export default EmailContactSelector
