import React from 'react'
import type { UseGridReturn } from '../hooks'
import { createGrid, useSubNavigation } from '../hooks'
import { GridDragOverlay } from './grid-drag-overlay'
import { GridContext } from '../context/grid-context'
import { render } from '../utils/test-utils'

describe('GridDragOverlay', () => {
    let grid: UseGridReturn

    beforeEach(() => {
        grid = createGrid()

        jest.spyOn(grid.selectors, 'selectDragIsActive').mockReturnValue(true)
        jest.spyOn(grid.selectors, 'selectDraggingRowIds').mockReturnValue(
            new Set(['101'])
        )
        jest.spyOn(grid.selectors, 'selectPreviewColumnId').mockReturnValue(
            'name'
        )
        jest.spyOn(grid.selectors, 'selectColumn').mockReturnValue({
            id: 'name',
            actualWidth: 300,
            data: {
                id: 'name',
                label: 'Name',
                cell: {
                    Renderer: jest
                        .fn()
                        .mockReturnValue(<div>Test Renderer</div>),
                },
            },
        })

        jest.spyOn(grid.selectors, 'selectRow').mockReturnValue({
            id: '101',
            name: 'Test Row',
        })
        jest.spyOn(grid.selectors, 'selectRowMeta').mockReturnValue({
            type: 'leaf',
        })
    })

    function renderComponent() {
        return render(
            <GridContext.Provider value={grid}>
                <GridDragOverlay />
            </GridContext.Provider>
        )
    }

    it('should render the drag overlay', () => {
        const { getByTestId } = renderComponent()

        const overlay = getByTestId('pvds-grid-drag-overlay')
        expect(overlay).toBeInTheDocument()
        expect(overlay).toHaveTextContent('Test Renderer')
    })

    it('should render using the value (if label and Renderer are not present)', () => {
        const valueCb = jest.fn().mockReturnValue('Test Value')
        jest.spyOn(grid.selectors, 'selectColumn').mockReturnValue({
            id: 'name',
            actualWidth: 300,
            data: {
                id: 'name',
                label: 'Name',
                cell: {
                    value: valueCb,
                },
            },
        })

        const { getByTestId } = renderComponent()

        expect(getByTestId('pvds-grid-drag-overlay')).toHaveTextContent(
            'Test Value'
        )

        expect(valueCb).toHaveBeenCalledWith({
            columnId: 'name',
            row: { id: '101', name: 'Test Row' },
            rowMeta: { type: 'leaf' },
        })
    })

    it('should render using the label (if Renderer is not present)', () => {
        const labelCb = jest.fn().mockReturnValue('Test Label')
        jest.spyOn(grid.selectors, 'selectColumn').mockReturnValue({
            id: 'name',
            actualWidth: 300,
            data: {
                id: 'name',
                label: 'Name',
                cell: {
                    value() {
                        return 'Test Value'
                    },
                    label: labelCb,
                },
            },
        })

        const { getByTestId } = renderComponent()

        expect(getByTestId('pvds-grid-drag-overlay')).toHaveTextContent(
            'Test Label'
        )
        expect(labelCb).toHaveBeenCalledWith({
            columnId: 'name',
            row: { id: '101', name: 'Test Row' },
            rowMeta: { type: 'leaf' },
            value: 'Test Value',
        })
    })

    it('should render using the Renderer', () => {
        const rendererCb = jest.fn().mockReturnValue(<div>Test Renderer</div>)
        jest.spyOn(grid.selectors, 'selectColumn').mockReturnValue({
            id: 'name',
            actualWidth: 300,
            data: {
                id: 'name',
                label: 'Name',
                cell: {
                    value() {
                        return 'Test Value'
                    },
                    label() {
                        return 'Test Label'
                    },
                    Renderer: rendererCb,
                },
            },
        })

        const { getByTestId } = renderComponent()

        expect(getByTestId('pvds-grid-drag-overlay')).toHaveTextContent(
            'Test Renderer'
        )
        expect(rendererCb).toHaveBeenCalledWith(
            {
                rowId: '101',
                columnId: 'name',
                tabIndex: -1,
                value: 'Test Value',
                label: 'Test Label',
            },
            undefined
        )
    })

    it('should render the error message if present', () => {
        jest.spyOn(grid.selectors, 'selectDragMessage').mockReturnValue(
            'You cannot drop here'
        )
        const { getByTestId } = renderComponent()

        const overlay = getByTestId('pvds-grid-drag-overlay')
        expect(overlay).toBeInTheDocument()
        expect(overlay).toHaveTextContent('Test RendererYou cannot drop here')
    })

    it('should render the drag overlay if Renderer uses sub-navigation', () => {
        jest.spyOn(grid.selectors, 'selectColumn').mockReturnValue({
            id: 'name',
            actualWidth: 300,
            data: {
                id: 'name',
                label: 'Name',
                cell: {
                    Renderer() {
                        useSubNavigation({
                            indexes: 3,
                            inlineFocusStylingEnabled: true,
                        })
                        return <div>Test Renderer with Sub Navigation</div>
                    },
                },
            },
        })

        const { getByTestId } = renderComponent()

        const overlay = getByTestId('pvds-grid-drag-overlay')
        expect(overlay).toHaveTextContent('Test Renderer with Sub Navigation')
    })
})
