import * as React from 'react'
import type {
    CellEditorParams,
    EditorConfirmPayload,
    GridRowData,
} from '../../types'
import type {
    ComboboxTreeCloseReason,
    ComboboxTreeOption,
    ComboboxTreeProps,
} from '@planview/pv-uikit'

import { useGridColumn, useGridSelector } from '../../context/grid-context'
import { useGrid } from '../../hooks'
import { cleanPropForSpread } from './utils'
import { StyledCombobox } from './styles'
import { AnchoredPortal } from './portal'

export type GridEditorComboboxTreeMultiProps<TDataModel extends GridRowData> =
    Omit<CellEditorParams<TDataModel>, 'value' | 'onConfirm'> &
        Omit<
            ComboboxTreeProps,
            | 'multiSelectable'
            | 'defaultValue'
            | 'onChange'
            | 'defaultOpen'
            | 'value'
            | 'disabled'
            | 'readOnly'
            | 'onClose'
            | 'onOpen'
            | 'onFocus'
            | 'onBlur'
        > & {
            /** value */
            value?: ComboboxTreeOption[]
            /**
             * confirm callback
             */
            onConfirm: (
                value: ComboboxTreeOption[],
                payload?: EditorConfirmPayload
            ) => void
        }

export const GridEditorComboboxTreeMulti = <TDataModel extends GridRowData>({
    value = [],
    onCancel,
    onConfirm,
    options,
    label = '',
    ...rest
}: GridEditorComboboxTreeMultiProps<TDataModel>) => {
    const wrapperRef = React.useRef<HTMLDivElement | null>(null)
    const column = useGridColumn(rest.columnId)
    const valueRef = React.useRef(value)

    React.useEffect(() => {
        valueRef.current = value
    }, [value])

    const handleChange = React.useCallback(
        (opt: ComboboxTreeOption[]) => {
            valueRef.current = opt
            onConfirm(opt, { continueEditing: 'current' })
        },
        [onConfirm]
    )

    const handleHidden = React.useCallback(() => {
        onCancel()
    }, [onCancel])

    const handleClose = React.useCallback(
        (reason: ComboboxTreeCloseReason) => {
            if (reason === 'confirm_click') {
                onConfirm(valueRef.current)
            } else if (!reason.includes('tab')) {
                onCancel()
            }
        },
        [onCancel, onConfirm]
    )

    const handleInputKeyDown = React.useCallback(
        (ev: React.KeyboardEvent<HTMLElement>) => {
            if (ev.key === 'Tab') {
                ev.preventDefault()
                ev.stopPropagation()
                onConfirm(valueRef.current, {
                    continueEditing: ev.shiftKey ? 'previous' : 'next',
                })
            }
            if (ev.key === 'Enter') {
                onConfirm(valueRef.current)
            }
        },
        [onConfirm]
    )

    React.useEffect(() => {
        setTimeout(() => {
            const el = wrapperRef.current
            if (el) {
                el.querySelector('input')?.focus()
            }
        }, 100)
    }, [])

    const { selectors } = useGrid()
    const height = useGridSelector(selectors.selectRowHeight)

    return (
        <AnchoredPortal
            ref={wrapperRef}
            minWidth={column?.actualWidth ?? 0}
            onHidden={handleHidden}
            onKeyDown={handleInputKeyDown}
        >
            <StyledCombobox
                {...cleanPropForSpread(rest)}
                $height={height}
                multiSelectable={true}
                label={label}
                options={options}
                defaultOpen
                onClose={handleClose}
                onChange={handleChange}
                value={value}
            />
        </AnchoredPortal>
    )
}
