import React from 'react'
import { render } from '../__utils/test-utils'
import userEvent from '@testing-library/user-event'

import { ProductSwitcher } from '.'
import { STUB_DATA, STUB_DATA_PLUS_ENSEMBLE } from './stub'
import { breakpoints } from '@planview/pv-utilities'

describe('ProductSwitcher', () => {
    describe('Initialization', () => {
        it('Should display loading if there are no apps', async () => {
            const { getByRole } = render(<ProductSwitcher products={[]} />)
            const trigger = getByRole('button', {
                name: 'Planview product switcher',
            })
            expect(trigger).toBeInTheDocument()

            await userEvent.click(trigger)

            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()

            expect(getByRole('menuitemradio')).toHaveAttribute(
                'aria-label',
                'Loading your Planview products'
            )
        })
        it('Should not display loading if apps have loaded', async () => {
            const { getAllByRole, getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            const trigger = getByRole('button', {
                name: 'Planview product switcher',
            })
            expect(trigger).toBeInTheDocument()

            await userEvent.click(trigger)

            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()

            expect(
                getAllByRole('menuitemradio')
                    .map((el) => el.getAttribute('aria-busy'))
                    .filter(Boolean)
            ).toHaveLength(0)
        })
        it('Should display organization branding if present', async () => {
            const { getByRole } = render(
                <ProductSwitcher
                    products={STUB_DATA}
                    organization={{
                        name: 'Example',
                        domain: 'example-domain',
                        avatar: { light: '/img/avatar', dark: '/img/avatar' },
                    }}
                />
            )
            const trigger = getByRole('button', {
                name: 'Planview product switcher',
            })
            expect(trigger).toBeInTheDocument()

            await userEvent.click(trigger)

            expect(
                getByRole('menu', {
                    name: 'Planview product switcher for Example domain example-domain',
                })
            ).toBeInTheDocument()
        })
    })

    describe('Breakpoints', () => {
        afterAll(() => {
            window.innerWidth = breakpoints.DESKTOP
        })
        it('Should not display mobile header in breakpoints.DESKTOP', async () => {
            window.innerWidth = breakpoints.DESKTOP

            const { getByRole, queryByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.click(
                getByRole('button', { name: 'Planview product switcher' })
            )
            expect(
                queryByRole('button', { name: 'Close' })
            ).not.toBeInTheDocument()
        })

        it('Should display mobile header in breakpoints.PHONE', async () => {
            window.innerWidth = breakpoints.PHONE
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.click(
                getByRole('button', { name: 'Planview product switcher' })
            )
            expect(getByRole('button', { name: 'Close' })).toBeInTheDocument()
        })
    })

    describe('Interaction', () => {
        it('open on enter', async () => {
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{enter}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
        })
        it('open on space', async () => {
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard(' ')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
        })
        it('open on arrow-down', async () => {
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
        })
        it('close on escape', async () => {
            const { getByRole, queryByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
            await userEvent.keyboard('{escape}')
            expect(
                queryByRole('menu', { name: 'Planview product switcher' })
            ).not.toBeInTheDocument()
        })
        it('close on trigger click', async () => {
            const { getByRole, queryByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            const trigger = getByRole('button', {
                name: 'Planview product switcher',
            })
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
            await userEvent.click(trigger)
            expect(
                queryByRole('menu', { name: 'Planview product switcher' })
            ).not.toBeInTheDocument()
        })
        it('open and navigate to third item (without Planview.me)', async () => {
            const { getByRole } = render(
                <ProductSwitcher
                    products={STUB_DATA.filter((p) => p.name !== 'planview_me')}
                />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')

            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
            //First item focused when opening list
            expect(
                getByRole('menuitemradio', {
                    name: `${STUB_DATA[0].label} ${STUB_DATA[0].secondaryLabel}`,
                })
            ).toHaveFocus()
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')

            //Third item focused when opening list
            expect(
                getByRole('menuitemradio', {
                    name: STUB_DATA[2].label,
                })
            ).toHaveFocus()
        })
        it('open and navigate to third item (with Planview.me)', async () => {
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')

            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()

            //First item focused when opening list
            expect(
                getByRole('menuitemradio', {
                    name: `Planview.Me My Planview Home`,
                })
            ).toHaveFocus()
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')

            //Third item focused when opening list
            expect(
                getByRole('menuitemradio', {
                    name: STUB_DATA[1].label,
                })
            ).toHaveFocus()
        })
        it('open and navigate to Ensemble', async () => {
            const spy = jest.fn()
            const { getByRole } = render(
                <ProductSwitcher
                    products={STUB_DATA_PLUS_ENSEMBLE}
                    onActivate={spy}
                />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')

            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()

            //First item focused when opening list
            expect(
                getByRole('menuitemradio', {
                    name: `Planview.Me My Planview Home`,
                })
            ).toHaveFocus()
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')

            //Second item focused
            expect(
                getByRole('menuitemradio', {
                    name: 'Planview.Me Labs',
                })
            ).toHaveFocus()

            await userEvent.keyboard('{Enter}')

            expect(spy).toHaveBeenCalledWith(STUB_DATA_PLUS_ENSEMBLE[0])
        })
        it('onActivate callback on space', async () => {
            const spy = jest.fn()
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} onActivate={spy} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Activate third item
            await userEvent.keyboard(' ')
            expect(spy).toHaveBeenCalledWith(STUB_DATA[1])
        })
        it('onActivate callback on enter', async () => {
            const spy = jest.fn()
            const { getByRole } = render(
                <ProductSwitcher products={STUB_DATA} onActivate={spy} />
            )
            await userEvent.keyboard('{Tab}')
            await userEvent.keyboard('{ArrowDown}')
            expect(
                getByRole('menu', { name: 'Planview product switcher' })
            ).toBeInTheDocument()
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Navigate down
            await userEvent.keyboard('{ArrowDown}')
            //Activate second item
            await userEvent.keyboard('{enter}')
            expect(spy).toHaveBeenCalledWith(STUB_DATA[1])
        })
    })
})
