import * as React from 'react'
import type {
    CellEditorParams,
    EditorConfirmPayload,
    GridRowData,
} from '../../types'
import type {
    ComboboxTreeCloseReason,
    ComboboxTreeOption,
    ComboboxTreeProps,
} from '@planview/pv-uikit'
import { cleanPropForSpread } from './utils'
import { StyledCombobox } from './styles'
import { useGridColumn, useGridSelector } from '../../context/grid-context'
import { useGrid } from '../../hooks'
import { AnchoredPortal } from './portal'

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

export const GridEditorComboboxTree = <TDataModel extends GridRowData>({
    value,
    onCancel,
    onConfirm,
    options,
    label = '',
    ...rest
}: GridEditorComboboxTreeProps<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 | null) => {
        valueRef.current = opt
    }, [])

    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]
    )

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

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

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

    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}
                label={label}
                options={options}
                defaultOpen
                onClose={handleClose}
                multiSelectable={undefined}
                onChange={handleChange}
                value={value}
            />
        </AnchoredPortal>
    )
}
