import React from 'react'
import { Checkbox } from '@planview/pv-uikit'
import styled from 'styled-components'
import { useGridSelector, useGridContext } from '../context/grid-context/hook'
import { defineMessages, useIntl } from 'react-intl'
import type { GridRowId } from '../types'
import { cursor, sizePx } from '@planview/pv-utilities'

const CheckboxLayout = styled(Checkbox)`
    height: 100%;

    /* Not ideal, but this lets the focus of the checkbox be cell-sized */
    > div {
        outline: none;
        height: 100%;
    }
`

const ExtraSpace = styled.div<{ $draggable?: boolean }>`
    width: ${sizePx.smallCompact};
    flex: 0 0 auto;
    ${(props) => (props.$draggable ? cursor.grab : undefined)};
    height: 100%;
`

const Wrapper = styled.div`
    display: flex;
    flex-direction: row;
    align-items: center;
    height: 100%;
`

const messages = defineMessages({
    labelToggleRow: {
        id: 'pvds.grid.rows.checkboxToggleRowLabel',
        defaultMessage: 'Toggle row selection',
        description:
            'Screen reader text for the toggle selection checkbox in row',
    },
})

export type GridCellCheckboxProps = {
    rowId: GridRowId
    tabIndex: number
}

export const GridCellCheckbox = ({
    rowId,
    tabIndex,
}: GridCellCheckboxProps) => {
    const intl = useIntl()
    const checkBoxRef = React.useRef<HTMLInputElement>(null)
    const shiftKeyRef = React.useRef(false)

    const { api, events, selectors } = useGridContext()
    const selectionState = useGridSelector((state) =>
        selectors.selectRowSelectionState(state, rowId)
    )
    const selectionMode = useGridSelector(selectors.selectSelectionMode)

    const isLoaded = useGridSelector((state) =>
        selectors.selectIsRowLoaded(state, rowId)
    )

    const spreadsheetMode = useGridSelector(selectors.selectIsSpreadsheet)
    const rowDragEnabled = useGridSelector(selectors.selectIsDraggingEnabled)

    const handleChange = React.useCallback(() => {
        api.selection.select(
            rowId,
            shiftKeyRef.current
                ? true
                : selectionState === 'all'
                  ? false
                  : true,
            false,
            shiftKeyRef.current
        )
        events.emit('onRowClick', rowId)
    }, [api, events, rowId, selectionState])

    const handleClick = React.useCallback((e: React.MouseEvent) => {
        e.stopPropagation()
        shiftKeyRef.current = e.shiftKey

        setTimeout(() => {
            shiftKeyRef.current = false
        }, 0)
    }, [])

    const handleExtraSpaceClick = React.useCallback(
        (e: React.MouseEvent) => {
            api.selection.select(
                rowId,
                e.shiftKey ? true : selectionState === 'all' ? false : true,
                false,
                e.shiftKey
            )
            events.emit('onRowClick', rowId)
        },
        [api, events, rowId, selectionState]
    )

    const keyDownHandler = React.useCallback(
        (ev: React.KeyboardEvent) => {
            if (ev.key === 'Enter') {
                ev.preventDefault()
                handleChange()
            }
        },
        [handleChange]
    )

    const checkbox = (
        <CheckboxLayout
            aria-label={intl.formatMessage(messages.labelToggleRow)}
            ref={checkBoxRef}
            tabIndex={tabIndex}
            size="small"
            indeterminate={selectionState === 'some'}
            selected={selectionState === 'all'}
            disabled={!isLoaded}
            onChange={handleChange}
            onKeyDown={keyDownHandler}
            onClick={handleClick}
        />
    )

    if (spreadsheetMode && (rowDragEnabled || selectionMode === 'single')) {
        return (
            <Wrapper
                data-grid-row-drag-handle={spreadsheetMode ? 'true' : undefined}
            >
                <ExtraSpace
                    onClick={handleExtraSpaceClick}
                    $draggable={rowDragEnabled}
                />
                {selectionMode === 'multi' && checkbox}
            </Wrapper>
        )
    }

    return checkbox
}
