import { useCallback } from 'react'
import { useGridContext, useGridSelector } from '../context/grid-context'
import type { GridRangeSelection, GridRowData } from '../types'
import type { SpreadsheetRangeCopy } from '../grids/spreadsheet-grid/types'

const RANGE_COPY_ANIMATION_DURATION = 300

export const useRangeCopy = (
    onRangeCopyIncoming: 'values' | 'labels' | SpreadsheetRangeCopy<any>,
    container: HTMLElement | null
) => {
    const grid = useGridContext()

    const isSpreadsheet = useGridSelector(grid.selectors.selectIsSpreadsheet)

    const onRangeCopy = useCallback(
        (
            _rangeSelection: GridRangeSelection<GridRowData>,
            data: {
                rowIds: GridRowData['id'][]
                columnIds: string[]
            },
            e: React.ClipboardEvent
        ) => {
            const doc = document.implementation.createHTMLDocument()
            const rows = doc.createElement('tbody')
            const rowsPlain: string[] = []
            const customData: {
                rowId: GridRowData['id']
                values: Record<
                    string,
                    { label: string; value: unknown; colSpan?: number }
                >
            }[] = []

            for (const rowId of data.rowIds) {
                const cells = doc.createElement('tr')
                const cellsPlain: string[] = []
                const customValues: Record<
                    string,
                    { label: string; value: unknown; colSpan?: number }
                > = {}
                const columnSpanConfigs =
                    grid.selectors.selectColumnSpanByRowId(
                        grid.getState(),
                        rowId
                    )
                for (const columnId of data.columnIds) {
                    const colSpanConfig = columnSpanConfigs?.get(columnId)

                    if (colSpanConfig?.skip || colSpanConfig?.as) {
                        cellsPlain.push('')
                        continue
                    }

                    const relatedColumns =
                        colSpanConfig?.positionColumnIds?.filter((id) =>
                            data.columnIds.includes(id)
                        ) ?? [columnId]

                    const cellValue = grid.api.content.getValue({
                        rowId,
                        columnId,
                    })
                    const cellLabel = grid.api.content.getLabel({
                        rowId,
                        columnId,
                    })
                    customValues[columnId] = {
                        label: cellLabel ?? '',
                        value: cellValue,
                        colSpan: relatedColumns.length,
                    }
                    const cellContent =
                        onRangeCopyIncoming === 'values' ? cellValue : cellLabel
                    const cell = doc.createElement('td')
                    if (relatedColumns.length > 1) {
                        cell.colSpan = relatedColumns.length
                    }
                    cell.textContent = cellContent ?? ''
                    cells.appendChild(cell)
                    cellsPlain.push(cellContent)
                }
                customData.push({ rowId, values: customValues })

                rows.appendChild(cells)
                rowsPlain.push(cellsPlain.join('\t'))
            }

            const table = doc.createElement('table')
            table.appendChild(rows)
            doc.body.appendChild(table)

            e.clipboardData?.setData('text/plain', rowsPlain.join('\n'))
            e.clipboardData?.setData('text/html', doc.documentElement.outerHTML)
            e.clipboardData?.setData(
                'application/x-pvds-grid',
                JSON.stringify(customData)
            )
        },
        [grid, onRangeCopyIncoming]
    )

    const handleCopy = useCallback(
        (e: React.ClipboardEvent) => {
            const state = grid.getState()
            const range = grid.selectors.selectRangeSelection(state)
            if (!range) {
                return
            }

            const rangeData = grid.selectors.selectRangeIds(state)

            e.preventDefault()

            if (typeof onRangeCopyIncoming === 'string') {
                onRangeCopy(range, rangeData, e)
            } else {
                onRangeCopyIncoming(range, rangeData, e)
            }

            container?.setAttribute('data-pvds-grid-range-copied', 'true')
            setTimeout(() => {
                container?.removeAttribute('data-pvds-grid-range-copied')
            }, RANGE_COPY_ANIMATION_DURATION)
        },
        [grid, container, onRangeCopy, onRangeCopyIncoming]
    )

    if (!isSpreadsheet) {
        return undefined
    }

    return handleCopy
}
