import { Divider, Menu, MenuItem } from '@blueprintjs/core'
import type { ItemListRenderer, ItemRenderer } from '@blueprintjs/select'
import { MultiSelect, renderFilteredItems } from '@blueprintjs/select'
import type { Team } from '@inject/graphql/fragment-types'
import {
  useCallback,
  useEffect,
  useMemo,
  useState,
  type Dispatch,
  type FC,
  type SetStateAction,
} from 'react'

interface TeamSelectorProps {
  teams: Team[]
  selectedTeamIds: string[]
  setSelectedTeamIds: Dispatch<SetStateAction<string[]>>
}

const TeamSelector: FC<TeamSelectorProps> = ({
  teams,
  selectedTeamIds,
  setSelectedTeamIds,
}) => {
  const [allSelected, setAllSelected] = useState(selectedTeamIds.length == 0)

  const [prevSelectedTeamIds, setPrevSelectedTeamIds] =
    useState<string[]>(selectedTeamIds)
  useEffect(() => {
    if (allSelected) {
      setPrevSelectedTeamIds(selectedTeamIds)
      setSelectedTeamIds(teams.map(team => team.id))
    } else {
      setSelectedTeamIds(prevSelectedTeamIds)
    }
  }, [allSelected])

  const itemListRenderer: ItemListRenderer<Team> = useCallback(
    listProps => {
      const menuContent = renderFilteredItems(listProps)

      return (
        <Menu
          role='listbox'
          {...listProps.menuProps}
          ulRef={listProps.itemsParentRef}
        >
          <MenuItem
            text='Select all'
            active={allSelected}
            onClick={() => setAllSelected(prev => !prev)}
            selected={allSelected}
            shouldDismissPopover={false}
            roleStructure='listoption'
          />
          <Divider />
          {menuContent}
        </Menu>
      )
    },
    [allSelected]
  )

  const itemRenderer: ItemRenderer<Team> = useCallback(
    (item, { handleClick, handleFocus, modifiers }) => (
      <MenuItem
        active={modifiers.active || allSelected}
        disabled={modifiers.disabled || allSelected}
        onClick={handleClick}
        onFocus={handleFocus}
        roleStructure='listoption'
        selected={selectedTeamIds.includes(item.id) || allSelected}
        shouldDismissPopover={false}
        text={item.name}
        key={item.id}
      />
    ),
    [allSelected, selectedTeamIds]
  )

  const selectedItems = useMemo(
    () => teams.filter(team => selectedTeamIds.includes(team.id)),
    [teams, selectedTeamIds]
  )

  const onItemSelect = useCallback(
    (team: Team) =>
      setSelectedTeamIds(prev => {
        if (prev.includes(team.id)) {
          return prev.filter(item => item !== team.id)
        }
        return [...prev, team.id]
      }),
    [setSelectedTeamIds]
  )

  return (
    <MultiSelect<Team>
      fill
      placeholder={allSelected ? 'All' : 'Select teams...'}
      itemRenderer={itemRenderer}
      items={teams}
      itemPredicate={(query, item) => item.name.startsWith(query)}
      onItemSelect={onItemSelect}
      onRemove={item =>
        setSelectedTeamIds(prev => prev.filter(teamId => teamId !== item.id))
      }
      popoverProps={{
        minimal: true,
      }}
      resetOnSelect
      selectedItems={allSelected ? [] : selectedItems}
      tagRenderer={item => item.name}
      itemListRenderer={itemListRenderer}
      popoverContentProps={{
        style: { maxHeight: '50vh', overflowY: 'auto', overflowX: 'hidden' },
      }}
    />
  )
}

export default TeamSelector
