import { Close } from '@mui/icons-material'
import { Box, Checkbox, CircularProgress, Typography } from '@mui/material'
import _ from 'lodash'
import { ReactNode, useCallback, useEffect, useState } from 'react'
import { useQuery } from 'react-query'
import { useImmer } from 'use-immer'
import FormLabel from '../FormLabel'
import { BpCheckedIcon, BpIcon } from '../SingleCheckbox'
import TextField from '../TextField'
import { IOption } from '../types'
import {
  StyledAnchor,
  StyledListContainer,
  StyledListItem,
  StyledPopover,
  StyledSelectedChip,
} from './styles'

const Anchor = ({ handleClick, id, label, required }) => {
  return (
    <Box>
      <FormLabel label={label} name={id ?? ''} required={required} />
      <StyledAnchor id={id} onClick={handleClick}>
        <Typography variant="subtitle1">Click to search</Typography>
      </StyledAnchor>
    </Box>
  )
}

const SelectedItems = ({ selectedItems, selectedLabel, onDelete }) => {
  if (!selectedItems?.length) return null
  return (
    <Box marginTop="10px">
      <FormLabel label={selectedLabel} name="form-label" required={false} />
      <Box sx={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
        {selectedItems?.map((item, index) => (
          <StyledSelectedChip
            deleteIcon={<Close />}
            key={index}
            label={item?.label}
            variant={'outlined'}
            onDelete={() => onDelete(item)}
          />
        ))}
      </Box>
    </Box>
  )
}

const OptionsList = ({ loading, menuItems, onSelected, selected }) => {
  const isIncluded = (id) => {
    return selected?.options?.find((item) => item.value == id)
  }

  const handleClick = (selectedOption) => {
    if (isIncluded(selectedOption.value)) {
      onSelected(
        selected?.options?.filter(
          (item) => item.value !== selectedOption.value,
        ),
      )
    } else {
      onSelected([...selected.options, selectedOption])
    }
  }

  if (loading)
    return <CircularProgress size={16} sx={{ textAlign: 'center' }} />

  if (!menuItems)
    return (
      <Typography
        sx={{ padding: '10px' }}
        variant="subtitle1"
        textAlign={'center'}
      >
        Start typing to search
      </Typography>
    )
  if (!menuItems?.length)
    return (
      <Typography
        sx={{ padding: '10px' }}
        variant="subtitle1"
        textAlign={'center'}
      >
        No results found
      </Typography>
    )

  return (
    <>
      {menuItems?.map((option, index) => (
        <StyledListItem key={index} onClick={() => handleClick(option)}>
          <Checkbox
            icon={isIncluded(option?.value) ? <BpCheckedIcon /> : <BpIcon />}
          />
          {option.label}
        </StyledListItem>
      ))}
    </>
  )
}

type SearchInputProps = {
  onChange: (value: IOption[]) => void
  initialOptions?: IOption[]
  searchQueryKey?: string
  selectedLabel?: ReactNode
  label: ReactNode
  fetchFn: (params: { [x: string]: string }) => Promise<IOption[]>
  required?: boolean
}

export default function AsyncSearchSelect({
  label,
  onChange,
  initialOptions = [],
  searchQueryKey = 'search',
  selectedLabel = 'Selected Items',
  fetchFn,
  required,
}: SearchInputProps) {
  const [search, setSearch] = useState('')
  const [width, setWidth] = useState(300)

  const { data: searchResults, isLoading } = useQuery(
    ['search', search],
    (params: any) => fetchFn({ ...params, [searchQueryKey]: search }),
    {
      enabled: Boolean(search),
    },
  )

  const [selected, setSelected] = useImmer({
    options: [],
  })

  const [open, setOpen] = useState(false)
  const [anchorEl, setAnchorEl] = useState<any>(null)
  const id = open ? 'simple-popover' : undefined

  const onSearchChange = (e) => {
    setSearch(e.target.value)
  }

  const handleClick = (event) => {
    const anchorWidth = event.target.getBoundingClientRect().width
    setWidth(anchorWidth)
    setOpen(true)
    setAnchorEl(event.currentTarget)
  }

  const handleClose = () => {
    setOpen(false)
  }

  const onSelected = (newValues) => {
    setSelected((s) => {
      s.options = newValues
    })
    if (onChange) onChange(newValues)
  }

  const onDeleteSelectedItem = (option) => {
    onSelected(selected?.options?.filter((item) => item.value !== option.value))
  }

  const debouncedChange = useCallback(_.debounce(onSearchChange, 300), [])

  useEffect(() => {
    setSelected((s) => {
      s.options = initialOptions
    })
  }, [initialOptions?.length])

  return (
    <Box>
      <Anchor
        handleClick={handleClick}
        id={id}
        label={label}
        required={required}
      />
      <SelectedItems
        onDelete={onDeleteSelectedItem}
        selectedItems={selected?.options}
        selectedLabel={selectedLabel}
      />
      <StyledPopover
        popoverWidth={width}
        open={open}
        id={id}
        anchorEl={anchorEl}
        onClose={handleClose}
      >
        <Box sx={{ padding: '14px' }}>
          <TextField
            size="small"
            onChange={debouncedChange}
            placeholder="Search"
            autoFocus={true}
          />
          <StyledListContainer>
            <OptionsList
              loading={isLoading}
              menuItems={searchResults}
              onSelected={onSelected}
              selected={selected}
            />
          </StyledListContainer>
        </Box>
      </StyledPopover>
    </Box>
  )
}
