import React, { useEffect } from 'react'
import { ProductSwitcherBridge } from './product-switcher-bridge'
import { NavigationBar } from './navigation-bar'
import { render, act } from '../__utils/test-utils'
import { LogoProjectPlace } from '../logos'
import { ToolbarSectionLeft } from '../section'
import { ToolbarButtonEmpty } from '../button'
import userEvent from '@testing-library/user-event'

function renderWithNavigationBar(component: React.ReactElement) {
    return render(component, {
        wrapper({ children }) {
            return (
                <NavigationBar
                    productSwitcher={children as React.JSX.Element}
                    logo={<LogoProjectPlace url="/" />}
                >
                    <ToolbarSectionLeft>
                        <ToolbarButtonEmpty>Sample button</ToolbarButtonEmpty>
                    </ToolbarSectionLeft>
                </NavigationBar>
            )
        },
    })
}

function ProductSwitcherBridgeWithFakeButton() {
    const ref = React.useRef<HTMLDivElement>(null)

    useEffect(() => {
        if (ref.current) {
            const button = document.createElement('button')
            button.setAttribute('aria-controls', 'app-switcher-list')
            button.tabIndex = -1
            button.innerHTML = 'Product Switcher'
            ref.current.appendChild(button)
        }
    })

    return <ProductSwitcherBridge ref={ref} />
}

describe('ProductSwitcherBridge', () => {
    it('should not participate in keyboard navigation if event not yet received', async () => {
        const { getByRole } = renderWithNavigationBar(
            <ProductSwitcherBridgeWithFakeButton />
        )

        await userEvent.keyboard('{Tab}{ArrowRight}{ArrowRight}')

        expect(getByRole('button', { name: 'Sample button' })).toHaveFocus()

        await userEvent.keyboard('{ArrowLeft}{ArrowLeft}')

        expect(
            getByRole('button', { name: 'Product Switcher' })
        ).not.toHaveFocus()
    })

    it('should participate in keyboard navigation one event is received', async () => {
        const { getByRole } = renderWithNavigationBar(
            <ProductSwitcherBridgeWithFakeButton />
        )

        act(() => {
            const event = new CustomEvent('productswitcher', {
                detail: { visible: true },
            })
            document.dispatchEvent(event)
        })

        await userEvent.keyboard('{Tab}{ArrowRight}{ArrowRight}')

        expect(getByRole('button', { name: 'Sample button' })).toHaveFocus()

        await userEvent.keyboard('{ArrowLeft}{ArrowLeft}')

        expect(getByRole('button', { name: 'Product Switcher' })).toHaveFocus()
    })

    it('should focus the product switcher when the div is focused', async () => {
        const { container, getByRole } = renderWithNavigationBar(
            <ProductSwitcherBridgeWithFakeButton />
        )

        act(() => {
            const event = new CustomEvent('productswitcher', {
                detail: { visible: true },
            })
            document.dispatchEvent(event)
        })

        /* Due to how react-roving-tabindex works, it will be focusable but not the first item */
        const wrapperDiv = container.querySelector('div[tabIndex="-1"]')!

        await userEvent.click(wrapperDiv)

        expect(getByRole('button', { name: 'Product Switcher' })).toHaveFocus()
    })
})
