import { useCallback, useMemo, useState } from 'react'
import { elem as elemArray, filter, lookup, uniq } from 'fp-ts/lib/Array'
import { flow, identity, not } from 'fp-ts/lib/function'
import { elem as elemOption, fold, fromPredicate } from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/pipeable'
import { unsafeCoerceToArray } from '@monorail/sharedHelpers/fp-ts-ext/ReadonlyArray'
import { isNotNil } from '@monorail/sharedHelpers/typeGuards'
import { DisplayType } from '@monorail/visualComponents/inputs/inputTypes'
import { FormMultiSelectInputProps } from './FormMultiSelectInput.types'
export function useFormMultiSelectInput(
props: FormMultiSelectInputProps,
) {
const {
display,
eq,
getSuggestedValues,
onChange,
options,
selectedOptions,
validateItem = fromPredicate(isNotNil),
modifySetSearchValue = identity,
} = props
const [searchValue, setSearchValue_] = useState('')
// TODO(eslint): fix exhaustive deps
// eslint-disable-next-line react-hooks/exhaustive-deps
const setSearchValue = useCallback(
flow(modifySetSearchValue, setSearchValue_),
[modifySetSearchValue],
)
const checkIsASuggestion = useMemo(
() => (as: Array) => (a: A): boolean => elemArray(eq)(a)(as),
[eq],
)
const suggestions = useMemo(
() =>
// Don't bother running the search in view mode
display === DisplayType.View
? []
: pipe(
getSuggestedValues(searchValue, options),
unsafeCoerceToArray,
filter(
pipe(
selectedOptions,
unsafeCoerceToArray,
checkIsASuggestion,
not,
),
),
),
[
display,
getSuggestedValues,
checkIsASuggestion,
options,
searchValue,
selectedOptions,
],
)
const removeOption = useCallback(
(value: A) => onChange(selectedOptions.filter(a => !eq.equals(value, a))),
[eq, onChange, selectedOptions],
)
const addItem = useCallback(
(item: A) => {
pipe(
item,
validateItem,
fold(
() => {},
item_ => onChange(uniq(eq)([item_, ...selectedOptions])),
),
)
setSearchValue('')
},
[validateItem, setSearchValue, onChange, eq, selectedOptions],
)
const checkIsHighlighted = useCallback(
(item: A, highlightedIndex: number | null) => {
if (highlightedIndex === null) {
return false
}
return elemOption(eq)(item, lookup(highlightedIndex, suggestions))
},
[eq, suggestions],
)
return {
searchValue,
setSearchValue,
suggestions,
removeOption,
addItem,
checkIsHighlighted,
} as const
}