import type { Column } from '../..'
import { Grid, GridCellBase, useSubNavigation } from '../..'
import { getNormalizedIndex, getNextSubFocusIndex } from './utils'
import { render } from '../../utils/test-utils'
import userEvent from '@testing-library/user-event'
import React from 'react'
import { theme } from '@planview/pv-utilities'
import { Tag } from '@planview/pv-uikit'

type RowData = { id: string; tags: number; label: string }

const rows: RowData[] = [
    {
        id: '1',
        label: 'Row 1',
        tags: 4,
    },
    {
        id: '2',
        label: 'Row 2',
        tags: 2,
    },
    {
        id: '3',
        label: 'Row 3',
        tags: 0,
    },
]
const columns: Column<RowData>[] = [
    {
        id: 'tags',
        label: 'Column 1',
        cell: {
            Renderer({ value, tabIndex }) {
                const { currentSubFocusIndex, setCurrentSubFocusIndex } =
                    useSubNavigation({
                        indexes: value,
                        inlineFocusStylingEnabled: true,
                    })

                return (
                    <GridCellBase tabIndex={tabIndex}>
                        {value
                            ? Array.from(Array(value), (e, i) => (
                                  <div
                                      key={i}
                                      tabIndex={
                                          currentSubFocusIndex === i ? 0 : -1
                                      }
                                      onClick={() => setCurrentSubFocusIndex(i)}
                                  >
                                      <Tag
                                          label={`Tag ${i + 1} ${
                                              currentSubFocusIndex === i
                                                  ? 'has focus'
                                                  : ''
                                          }`}
                                          color={theme.bloodOrange100}
                                      />
                                  </div>
                              ))
                            : 'No tags!'}
                    </GridCellBase>
                )
            },
        },
    },
    {
        id: 'label',
        label: 'Name',
    },
]

describe('grid-sub-navigation-context', () => {
    describe('utils', () => {
        describe('getNormalizedIndex', () => {
            it('return 0 from first', () => {
                expect(getNormalizedIndex('first', 3)).toBe(0)
            })
            it('return last', () => {
                expect(getNormalizedIndex('last', 5)).toBe(4)
            })
            it('return number', () => {
                expect(getNormalizedIndex(3, 5)).toBe(3)
            })
        })
        describe('getNextSubFocusIndex', () => {
            it('should move right from first', () => {
                expect(getNextSubFocusIndex('right', 'first', 4)).toBe(1)
            })
            it('should not move right from last', () => {
                expect(getNextSubFocusIndex('right', 'last', 4)).toBe(3)
            })
            it('should move left from last', () => {
                expect(getNextSubFocusIndex('left', 'last', 4)).toBe(2)
            })
            it('should return -1 when moving left if no sub-navigation available', () => {
                expect(getNextSubFocusIndex('left', 'last', 0)).toBe(-1)
            })
            it('should return -1 when moving right if no sub-navigation available', () => {
                expect(getNextSubFocusIndex('right', 'last', 0)).toBe(-1)
            })
        })
    })
    describe('navigation', () => {
        it('should navigate within cell if multiple stops and move out after last stop', async () => {
            const { getByText } = render(
                <Grid selectionMode="none" rows={rows} columns={columns} />
            )
            await userEvent.keyboard('{Tab}{ArrowDown}')
            expect(getByText('Tag 1 has focus')).toBeInTheDocument()
            await userEvent.keyboard('{ArrowRight}{ArrowRight}')
            expect(getByText('Tag 3 has focus')).toBeInTheDocument()
            await userEvent.keyboard('{ArrowLeft}')
            expect(getByText('Tag 2 has focus')).toBeInTheDocument()
            await userEvent.keyboard('{ArrowRight}{ArrowRight}')
            expect(getByText('Tag 4 has focus')).toBeInTheDocument()
            await userEvent.keyboard('{ArrowRight}')
            expect(getByText('Row 1')).toHaveFocus()
        })
        it('should navigate to last sub-index in cell when entering from cell to the right', async () => {
            const { getByText } = render(
                <Grid selectionMode="none" rows={rows} columns={columns} />
            )
            await userEvent.keyboard('{Tab}{ArrowRight}{ArrowDown}')
            expect(getByText('Row 1')).toHaveFocus()
            await userEvent.keyboard('{ArrowLeft}')
            expect(getByText('Tag 4 has focus')).toBeInTheDocument()
        })
        it('should navigate correctly between cells with differing amount of sub-indexes', async () => {
            const { getByText } = render(
                <Grid selectionMode="none" rows={rows} columns={columns} />
            )
            //Navigate to last tag in first row (row contains 4 tags)
            await userEvent.keyboard('{Tab}{ArrowRight}{ArrowDown}{ArrowLeft}')
            expect(getByText('Tag 4 has focus')).toBeInTheDocument()
            //Navigate down to second row (row contains 2 tags)
            await userEvent.keyboard('{ArrowDown}')
            expect(getByText('Tag 2 has focus')).toBeInTheDocument()
            //Navigate up again to first row
            await userEvent.keyboard('{ArrowUp}')
            expect(getByText('Tag 4 has focus')).toBeInTheDocument()
        })
        it('should navigate after setting sub-focus on click', async () => {
            const { getByText } = render(
                <Grid selectionMode="none" rows={[rows[0]]} columns={columns} />
            )
            await userEvent.click(getByText('Tag 3'))
            expect(getByText('Tag 3 has focus')).toBeInTheDocument()
            await userEvent.keyboard('{ArrowLeft}')
            expect(getByText('Tag 2 has focus')).toBeInTheDocument()
        })
        it('should use tabIndex from Renderer if no indexes in cell', async () => {
            const { getByText } = render(
                <Grid selectionMode="none" rows={rows} columns={columns} />
            )
            await userEvent.keyboard('{Tab}{ArrowDown}{ArrowDown}{ArrowDown}')
            expect(getByText('No tags!')).toHaveFocus()
        })
    })
})
