import * as React from 'react'
import ResizeContext, {
    WrappingParentContext,
    GenericContext,
    MoreMenuContext,
} from '../utils/context'
import type { DisplayOnType } from '../utils'
import { uniqueId, DISPLAY_ON_TABLET_PORTRAIT } from '../utils'
import { useFocusEffect, useRovingTabIndex } from '../react-roving-tabindex'

export type ToolbarItemProps = {
    /**
     * Target display of this item. Choose 'phone' to prevent collapsing.
     */
    displayOn?: DisplayOnType
    /**
     * Expects one \`ToolbarItemView\` element and one \`MoreMenuView\` element
     */
    children:
        | [
              React.ReactElement<ToolbarItemViewProps<HTMLElement>>,
              React.ReactElement<ToolbarItemCollapsedViewProps>,
          ]
        | React.ReactElement<ToolbarItemViewProps<HTMLElement>>
}

export const ToolbarItem = React.memo(
    ({
        children,
        displayOn = DISPLAY_ON_TABLET_PORTRAIT,
    }: ToolbarItemProps) => {
        const { shouldDisplay } = React.useContext(ResizeContext)
        const showMoreMenuItem = shouldDisplay(displayOn)

        const state = React.useMemo(
            () => ({ displayOn, showMoreMenuItem }),
            [displayOn, showMoreMenuItem]
        )

        return (
            <GenericContext.Provider value={state}>
                {children}
            </GenericContext.Provider>
        )
    },
    (prev, next) =>
        prev.children === next.children && prev.displayOn === next.displayOn
)

ToolbarItem.displayName = 'ToolbarItem'

type ToolbarItemViewProps<T> = {
    /**
     * @deprecated This had been introduced as a temporary fix. We plan to
     * fix more fully in a future release which will result in this prop being removed. */
    refOverride?: React.MutableRefObject<T | null>

    /**
     * @deprecated Pass disabled state directly to the child
     */
    disabled?: boolean
    /**
     * Render-prop function to return children
     */
    children: (
        ref: React.MutableRefObject<T | null>,
        props: {
            /** @deprecated Pass disabled state directly to the child */
            disabled?: boolean
            showLabels: boolean
            toolbarItemProps: {
                onKeyDown: React.KeyboardEventHandler<T>
                onClick: React.MouseEventHandler<T>
                tabIndex: number
                focused: boolean
            }
        }
    ) => React.JSX.Element
}

function ChildWrap<T extends HTMLElement>({
    refOverride,
    children,
    disabled,
}: ToolbarItemViewProps<T>) {
    const { showLabels } = React.useContext(ResizeContext)
    const innerRef: React.MutableRefObject<T | null> = React.useRef(null)

    const ref = refOverride ?? innerRef

    const [tabIndex, focused, handleKeyDown, handleClick] = useRovingTabIndex(
        ref as React.RefObject<T>,
        false
    )

    useFocusEffect(focused, ref as React.RefObject<T>)

    return children(ref, {
        showLabels,
        disabled,
        toolbarItemProps: {
            tabIndex,
            focused,
            onKeyDown: handleKeyDown,
            onClick: handleClick,
        },
    })
}

export function ToolbarItemView<T extends HTMLElement>(
    props: ToolbarItemViewProps<T>
) {
    const { inMoreMenuSection } = React.useContext(MoreMenuContext)
    const { showMoreMenuItem } = React.useContext(GenericContext)
    const { wrappedInToolbarParent } = React.useContext(WrappingParentContext)

    return inMoreMenuSection &&
        showMoreMenuItem &&
        !wrappedInToolbarParent ? null : (
        <ChildWrap {...props}>{props.children}</ChildWrap>
    )
}

export type ToolbarItemCollapsedViewProps = {
    /**
     * Needs to be a compatible child to the pv-uikit Dropdown component
     */
    children: React.ReactElement
}

export const ToolbarItemCollapsedView = React.memo(
    ({ children }: ToolbarItemCollapsedViewProps) => {
        const { displayOn } = React.useContext(GenericContext)
        const { wrappedInToolbarParent } = React.useContext(
            WrappingParentContext
        )
        const { dispatch } = React.useContext(MoreMenuContext)
        const idRef = React.useRef<string | null>(null)

        const getId = () => {
            if (!idRef.current) {
                idRef.current = uniqueId()
            }
            return idRef.current
        }

        React.useEffect(() => {
            const id = getId()

            if (!wrappedInToolbarParent) {
                dispatch({
                    type: 'REGISTER_CHILD',
                    child: children,
                    displayOn,
                    id,
                })
            }

            return () => {
                dispatch({ type: 'UNREGISTER_CHILD', id })
            }
            // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [])

        React.useEffect(() => {
            if (!wrappedInToolbarParent) {
                dispatch({
                    type: 'UPDATE_CHILD',
                    child: children,
                    id: getId(),
                    displayOn,
                })
            }
            // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [children, displayOn])

        return null
    }
)

ToolbarItemCollapsedView.displayName = 'ToolbarItemCollapsedView'
