import React from 'react'
import { render } from '../utils/test-utils'
import type { GridEditorInputProps } from './input'
import { GridEditorInput } from './input'
import userEvent from '@testing-library/user-event'

const baseProps = {
    rowId: '1',
    mode: 'editing' as GridEditorInputProps<any>['mode'],
    tabIndex: 0,
    label: '',
    value: 'text',
    columnId: 'name',
}

describe('GridEditorInput', () => {
    let onConfirm: jest.Mock
    let onCancel: jest.Mock

    beforeEach(() => {
        onConfirm = jest.fn()
        onCancel = jest.fn()
    })

    function renderInput(props: Partial<GridEditorInputProps<any>> = {}) {
        return render(
            <GridEditorInput
                {...baseProps}
                onCancel={onCancel}
                onConfirm={onConfirm}
                {...props}
            />
        )
    }

    it('should render', () => {
        const { queryByRole } = renderInput()
        expect(queryByRole('textbox')).toBeInTheDocument()
    })

    it('should support editing (commit with Tab)', async () => {
        renderInput()

        await userEvent.keyboard('{Tab}New value{Tab}')

        expect(onConfirm).toHaveBeenCalledWith('New value', {
            continueEditing: 'next',
        })
    })

    it('should support editing (commit with Shift+Tab)', async () => {
        renderInput()

        await userEvent.keyboard('{Tab}New value{Shift>}{Tab}{/Shift}')

        expect(onConfirm).toHaveBeenCalledWith('New value', {
            continueEditing: 'previous',
        })
    })

    it('should support editing (commit with Enter)', async () => {
        renderInput()

        await userEvent.keyboard('{Tab}New value{Enter}')

        expect(onConfirm).toHaveBeenCalledWith('New value')
    })

    it('should support cancelling an edit with Esc', async () => {
        renderInput()

        await userEvent.keyboard('{Tab}New value{Escape}')

        expect(onConfirm).not.toHaveBeenCalled()
        expect(onCancel).toHaveBeenCalled()
    })

    it('should support controlled rendering', async () => {
        const Wrapper = () => {
            const [value, setValue] = React.useState('')

            return (
                <GridEditorInput
                    {...baseProps}
                    value={value}
                    controlled
                    onChange={(val) =>
                        setValue(val.substring(0, 5).toLowerCase())
                    }
                    onCancel={onCancel}
                    onConfirm={onConfirm}
                />
            )
        }

        render(<Wrapper />)

        await userEvent.keyboard('{Tab}New value{Tab}')

        expect(onConfirm).toHaveBeenCalledWith('new v', {
            continueEditing: 'next',
        })
    })
})
