import * as React from 'react'
import type {
    ButtonProps,
    DropdownMenuCloseReason,
    DropdownMenuProps,
    DropdownTriggerProps,
    MenuProps,
} from '@planview/pv-uikit'
import { ButtonEmpty, DropdownMenu, Menu } from '@planview/pv-uikit'
import { useGridApi } from '../context/grid-context'

import styled from 'styled-components'

const CCell = styled.div`
    height: 100%;
    width: 100%;
`

const StyledButtonEmpty = styled(ButtonEmpty)`
    height: 100%;
`

type CellDropdownMenuTriggerConfig = Omit<
    ButtonProps,
    | 'aria-haspopup'
    | 'aria-controls'
    | 'aria-expanded'
    | 'aria-disabled'
    | 'children'
    | 'size'
> & {
    /** Label of trigger */
    label?: string | number
}

export type GridCellDropdownMenuProps = {
    /**
     * Accessible tab index. You should generally pass through the tabIndex
     * provided to the Renderer component.
     */
    tabIndex: number
    /**
     * Trigger configuration for dropdown menu. This is similar to DropdownMenu
     * except that you cannot provide a custom function and you can supply a tooltip.
     *
     * When omitted, it will default to showing the label and a caret
     */
    trigger?: CellDropdownMenuTriggerConfig
} & Omit<DropdownMenuProps, 'trigger' | 'active'>

type BaseMenu = Omit<MenuProps, 'children'>

type GridCellDropdownMenuBaseProps<
    TMenuProps extends Partial<BaseMenu> = MenuProps,
> = Pick<
    GridCellDropdownMenuProps,
    'trigger' | 'tabIndex' | 'onOpen' | 'onClose'
> & {
    MenuComponent: React.ComponentType<TMenuProps>
    menuProps: TMenuProps
}

/* Prevent the grid from selecting the row */
const stopPropagation: React.MouseEventHandler<HTMLElement> = (ev) =>
    ev.stopPropagation()

const GridCellDropdownMenuBase = <TMenuProps extends BaseMenu = MenuProps>({
    tabIndex,
    trigger,
    onClose,
    onOpen,
    MenuComponent,
    menuProps,
}: GridCellDropdownMenuBaseProps<TMenuProps>) => {
    const api = useGridApi()
    const [open, setOpen] = React.useState(false)

    const handleOpen = React.useCallback(() => {
        setOpen(true)
        onOpen?.()
    }, [onOpen])

    const handleClose = React.useCallback(
        (reason: DropdownMenuCloseReason) => {
            setOpen(false)
            onClose?.(reason)
        },
        [onClose]
    )

    const renderTrigger = React.useCallback<
        (trigger: DropdownTriggerProps) => React.JSX.Element
    >(
        (triggerProps) => {
            const { label: triggerLabel, ...triggerConfig } = trigger || {
                label: menuProps.label,
                withCaret: true,
            }
            return (
                <StyledButtonEmpty
                    {...triggerConfig}
                    {...triggerProps}
                    tabIndex={tabIndex}
                    activated={triggerProps['aria-expanded']}
                    onKeyDown={(e) => {
                        if (e.key === 'Enter' || e.key === ' ') {
                            return triggerProps.onKeyDown(e)
                        }
                    }}
                    onClick={stopPropagation}
                >
                    {triggerLabel}
                </StyledButtonEmpty>
            )
        },
        [menuProps.label, tabIndex, trigger]
    )

    React.useEffect(() => {
        if (open) {
            api.navigation.disable()
            return () => {
                api.navigation.enable()
            }
        }
    }, [api.navigation, open])

    return (
        <CCell role="presentation" onClick={stopPropagation}>
            <DropdownMenu.Base
                onOpen={handleOpen}
                onClose={handleClose}
                trigger={renderTrigger}
                MenuComponent={MenuComponent}
                menuProps={menuProps}
            />
        </CCell>
    )
}

const GridCellDropdownMenuImpl = ({
    tabIndex,
    trigger,
    onClose,
    onOpen,
    ...menuProps
}: GridCellDropdownMenuProps) => (
    <GridCellDropdownMenuBase
        tabIndex={tabIndex}
        onOpen={onOpen}
        onClose={onClose}
        trigger={trigger}
        MenuComponent={Menu}
        menuProps={menuProps}
    />
)

const GridCellDropdownMenuMemo = React.memo(GridCellDropdownMenuImpl) as any

GridCellDropdownMenuMemo.displayName = 'GridCellDropdownMenu'
GridCellDropdownMenuMemo.Base = GridCellDropdownMenuBase

type GridCellDropdownMenuComposite = typeof GridCellDropdownMenuImpl & {
    Base: typeof GridCellDropdownMenuBase
}

export const GridCellDropdownMenu =
    GridCellDropdownMenuMemo as GridCellDropdownMenuComposite
