import React, { useMemo } from 'react'
import { useGridComponents } from '../context/grid-components-context/hook'
import { useColumnResize } from '../hooks/use-column-resize'
import { useGridContext, useGridSelector } from '../context/grid-context/hook'
import { useFocusHandler } from '../hooks'
import { size, useIsFocusVisible } from '@planview/pv-utilities'
import { GridHeaderGroupCellDefaultRenderer } from '../renderers/'
import type { GridRowId } from '../types'
import { useDraggable } from '@dnd-kit/core'
import { DRAG_TYPE_HEADER_GROUP_CELL } from './grid-drag-controller'
import { createSelector } from 'reselect'

export type GridHeaderGroupCellProps = {
    columnId: string
    columnIndex: number
    rowId: GridRowId
    height: number
    columnSpan: number
    tabIndex?: number
    placeholder?: boolean
    lastPlaceholder?: boolean
}

const stopPropagation: React.MouseEventHandler = (e): void => {
    e.stopPropagation()
}

export const GridHeaderGroupCell = ({
    columnId,
    columnIndex,
    rowId,
    height,
    columnSpan,
    placeholder = false,
    lastPlaceholder = false,
}: GridHeaderGroupCellProps) => {
    const {
        GridHeaderGroupCellLayout,
        GridCellFocusLayout,
        GridColumnMoveHandle,
        GridColumnResizeHandle,
    } = useGridComponents()

    const { selectors } = useGridContext()
    const { actualWidth, data: column } = useGridSelector((state) =>
        selectors.selectColumn(state, columnId)
    )

    const focusProps = useIsFocusVisible()

    const [hovering, setHovering] = React.useState(false)

    const [hasFocus, handleFocus] = useFocusHandler(columnId, 'header', rowId)

    const onEnter = React.useCallback(() => setHovering(true), [])
    const onLeave = React.useCallback(() => setHovering(false), [])

    const [resizing, resizeHandlers] = useColumnResize(column.id, actualWidth)

    const draggingSelector = useMemo(
        () =>
            createSelector([selectors.selectHeaderHierarchy], ({ groups }) => {
                const { columnIds: columnsDragged } = groups.find(
                    (g) => g.id === columnId
                )!

                const groupsDragged = groups.reduce(
                    (prev, curr) => {
                        if (
                            curr.childIds &&
                            curr.parentIds.includes(columnId)
                        ) {
                            prev.push(curr.id)
                        }
                        return prev
                    },
                    [columnId]
                )

                return { columnsDragged, groupsDragged }
            }),
        [columnId, selectors]
    )

    const { columnsDragged, groupsDragged } = useGridSelector(draggingSelector)

    const {
        attributes,
        listeners,
        setNodeRef,
        setActivatorNodeRef,
        isDragging,
    } = useDraggable({
        id: columnId,
        data: {
            type: DRAG_TYPE_HEADER_GROUP_CELL,
            columnsDragged,
            groupsDragged,
            column,
            height,
            offsetY: height - size.small,
        },
        disabled: !column.movable,
    })

    React.useEffect(() => {
        if (isDragging) {
            setHovering(false)
        }
    }, [isDragging])

    const onPointerDown = listeners?.onPointerDown

    const handlePointerDown = React.useCallback<
        React.PointerEventHandler<HTMLElement>
    >(
        (e) => {
            handleFocus()
            onPointerDown?.(e)
        },
        [handleFocus, onPointerDown]
    )

    const sticky =
        column.sticky === 'left' || column.sticky === 'right'
            ? column.sticky
            : null

    const stickyOffset = useGridSelector((state) =>
        selectors.selectColumnGroupStickyOffset(state, columnId)
    )

    const extraStyle: Partial<React.CSSProperties> | null = sticky
        ? {
              [sticky]: stickyOffset,
          }
        : null

    return (
        <GridHeaderGroupCellLayout
            ref={setNodeRef}
            {...attributes}
            role="columnheader"
            aria-roledescription={undefined}
            aria-colindex={columnIndex + 1}
            scope="col"
            style={{
                ...extraStyle,
                width: actualWidth,
                height: height,
                transform: `translateY(-${height - size.small}px)`,
            }}
            tabIndex={hasFocus ? 0 : -1}
            {...listeners}
            onMouseEnter={onEnter}
            onMouseLeave={onLeave}
            onPointerDown={handlePointerDown}
            $sortable={column.sortable}
            $movable={column.movable}
            $placeholder={placeholder}
            $hovering={!placeholder && hovering}
            $resizing={!!resizing}
            data-current-cell={hasFocus ? 'true' : undefined}
            $sticky={!!sticky}
            onFocus={focusProps.onFocus}
            onBlur={focusProps.onBlur}
            colSpan={columnSpan > 1 ? columnSpan : undefined}
        >
            <GridCellFocusLayout
                $focusVisible={focusProps.focusVisible && hasFocus}
                style={{
                    paddingTop: height - size.small,
                }}
                $rightBorder={!(placeholder && !lastPlaceholder)}
            >
                {!placeholder && (
                    <GridHeaderGroupCellDefaultRenderer
                        tabIndex={-1}
                        columnId={columnId}
                    />
                )}
                {column.movable && hovering && !resizing && !placeholder ? (
                    <GridColumnMoveHandle
                        ref={setActivatorNodeRef}
                        horizontal
                        $resizable={!!column.resizable}
                    />
                ) : null}
                {((column.resizable && hovering) || resizing) &&
                !placeholder ? (
                    <GridColumnResizeHandle
                        $resizing={!!resizing}
                        onClick={stopPropagation}
                        {...resizeHandlers}
                    />
                ) : null}
            </GridCellFocusLayout>
        </GridHeaderGroupCellLayout>
    )
}

export const GridHeaderGroupCellMemo = React.memo(
    GridHeaderGroupCell
) as typeof GridHeaderGroupCell
