import React, { useCallback, useMemo, useState } from 'react'

import { userServiceListUsers } from 'apiClient/services/core-server'
import type { V1User } from 'apiClient/services/core-server/interface'
import DebounceSelect from 'components/DebounceSelect/DebounceSelect'

type UserOption = {
  label: string
  value: string
}

type UserSearchInputValue = string | string[]

export interface UserSearchInputProps {
  value?: UserSearchInputValue
  onChange?: (value?: UserSearchInputValue) => void
  disabled?: boolean
  placeholder?: string
  className?: string
  style?: React.CSSProperties
  allowClear?: boolean
  mode?: 'multiple'
}

const DEFAULT_PLACEHOLDER = 'Search by user email'
const DEFAULT_PAGE_SIZE = 20

function formatUserLabel(user: V1User) {
  const email = user.email

  if (!email) {
    return ''
  }

  const userName = user.larkUserName

  return userName ? `${userName} (${email})` : email
}

const UserSearchInput: React.FC<UserSearchInputProps> = ({
  value,
  onChange,
  disabled,
  placeholder = DEFAULT_PLACEHOLDER,
  className,
  style,
  allowClear = true,
  mode
}) => {
  const [innerValue, setInnerValue] = useState<UserSearchInputValue>()
  const [selectedOptions, setSelectedOptions] = useState<UserOption[]>([])
  const isMultiple = mode === 'multiple'

  const currentValue = value ?? innerValue

  const fetchOptions = useCallback(async (search: string) => {
    const normalizedSearch = search.trim()

    if (!normalizedSearch) {
      return []
    }

    const { data } = await userServiceListUsers({
      userKeyword: normalizedSearch,
      page: 1,
      perPage: DEFAULT_PAGE_SIZE
    })

    return (data.users || [])
      .filter((item) => item.email)
      .map((item) => {
        const email = item.email!

        return {
          label: formatUserLabel(item),
          value: email
        }
      })
  }, [])

  const selectValue = useMemo(() => {
    if (
      !currentValue ||
      (Array.isArray(currentValue) && currentValue.length === 0)
    ) {
      return undefined
    }

    const currentValues = Array.isArray(currentValue)
      ? currentValue
      : [currentValue]

    const mappedOptions = currentValues.map((item) => {
      return (
        selectedOptions.find(
          (selectedOption) => selectedOption.value === item
        ) || {
          value: item,
          label: item
        }
      )
    })

    return isMultiple ? mappedOptions : mappedOptions[0]
  }, [currentValue, isMultiple, selectedOptions])

  const handleChange = (option?: UserOption | UserOption[]) => {
    const nextOptions = Array.isArray(option) ? option : option ? [option] : []
    const nextSelectedOptions = nextOptions.map((selectedOption) => ({
      value: selectedOption.value.toString(),
      label: selectedOption.label.toString()
    }))
    const nextValue = isMultiple
      ? nextSelectedOptions.map((selectedOption) => selectedOption.value)
      : nextSelectedOptions[0]?.value

    if (value === undefined) {
      setInnerValue(nextValue)
    }

    setSelectedOptions(nextSelectedOptions)
    onChange?.(nextValue)
  }

  return (
    <DebounceSelect<UserOption>
      value={selectValue}
      mode={mode}
      disabled={disabled}
      placeholder={placeholder}
      className={className}
      style={style}
      allowClear={allowClear}
      showSearch
      fetchOptions={fetchOptions}
      onChange={handleChange}
    />
  )
}

export default UserSearchInput
export { UserSearchInput }
