import React from 'react'
import { useGridComponents } from '../context/grid-components-context'
import { useGridContext, useGridSelector } from '../context/grid-context'
import { getGroupIndex } from '../state/reducer/column-utils'
import { GridHeaderGroupCellSpacer } from './grid-header-group-cell-spacer'
import { size } from '@planview/pv-utilities'
import { useDndContext } from '@dnd-kit/core'

const GridHeaderImpl = <T,>() => {
    const {
        GridHeadLayout,
        GridHeaderRow,
        GridHeaderCell,
        GridHeaderGroupCell,
    } = useGridComponents()

    const { selectors } = useGridContext()
    const columnIds = useGridSelector(selectors.selectColumnIds)
    const headerRowIds = useGridSelector(selectors.selectHeaderRowIds)
    const headerHierarchy = useGridSelector(selectors.selectHeaderHierarchy)
    const areHeadersHidden = useGridSelector(selectors.selectAreHeadersHidden)
    const { levels, groups } = headerHierarchy
    const { active } = useDndContext()

    const columnsBeingDragged = React.useMemo(() => {
        if (active?.data.current?.columnsDragged) {
            return [...(active.data.current?.columnsDragged as string[])].sort(
                (a, b) => columnIds.indexOf(a) - columnIds.indexOf(b)
            )
        }
        return []
    }, [active, columnIds])

    const groupsBeingDragged = React.useMemo(() => {
        if (active) {
            return (active.data.current?.groupsDragged as string[]) ?? []
        }
        return []
    }, [active])

    const columnHeaders = React.useMemo(() => {
        const ret: React.ReactNode[] = []
        const groupsAdded = new Set<string>()
        if (levels) {
            Array.from({
                length: levels,
            }).forEach((_, index) => {
                const rowId = headerRowIds[index]
                const level = levels - index
                const groupIndexes = groups
                    .filter((g) => g.level === level)
                    .map((g) => ({
                        ...g,
                        index: getGroupIndex(g.columnIds, columnIds),
                    }))

                const groupElements: React.JSX.Element[] = []
                columnIds.forEach((cId, cIndex) => {
                    const nextGroup = groupIndexes.find(
                        (record) =>
                            record.index === cIndex ||
                            (record.index < cIndex &&
                                cIndex < record.index + record.width)
                    )
                    if (nextGroup && !groupsAdded.has(nextGroup.id)) {
                        groupsAdded.add(nextGroup.id)
                        groupElements.push(
                            <GridHeaderGroupCell
                                key={nextGroup.id}
                                placeholder={groupsBeingDragged.includes(
                                    nextGroup.id
                                )}
                                lastPlaceholder={nextGroup.columnIds.includes(
                                    columnsBeingDragged[
                                        columnsBeingDragged.length - 1
                                    ]
                                )}
                                rowId={rowId}
                                columnId={nextGroup.id}
                                columnIndex={nextGroup.index}
                                height={
                                    nextGroup.parentIds.length ||
                                    nextGroup.level === levels
                                        ? size.small
                                        : size.small * 2
                                }
                                columnSpan={nextGroup.columnIds.length}
                            />
                        )
                    }
                    if (!nextGroup) {
                        groupElements.push(
                            <GridHeaderGroupCellSpacer
                                key={cIndex}
                                columnId={cId}
                            />
                        )
                    }
                })
                ret.push(
                    <GridHeaderRow rowId={rowId} key={index}>
                        {groupElements}
                    </GridHeaderRow>
                )
            })
        }
        return ret.length ? ret : null
    }, [
        levels,
        headerRowIds,
        groups,
        columnIds,
        GridHeaderRow,
        GridHeaderGroupCell,
        groupsBeingDragged,
        columnsBeingDragged,
    ])

    return (
        <GridHeadLayout role="rowgroup" $hidden={areHeadersHidden}>
            {columnHeaders}
            <GridHeaderRow rowId={headerRowIds[headerRowIds.length - 1]}>
                {columnIds.map((columnId) => (
                    <GridHeaderCell
                        key={columnId}
                        placeholder={columnsBeingDragged.includes(columnId)}
                        lastPlaceholder={
                            columnsBeingDragged[
                                columnsBeingDragged.length - 1
                            ] === columnId
                        }
                        columnId={columnId}
                    />
                ))}
            </GridHeaderRow>
        </GridHeadLayout>
    )
}

export const GridHeader = React.memo(GridHeaderImpl)
