import React from 'react';
import { screen, render, waitFor, act, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import BrowseToSource from './BrowseToSource';
import { mockSource } from '../__mocks__/MockModels';
import { ResourceBrowserSource } from '../types';

describe('BrowseToSource', () => {
    it('Render empty fragment if no sources are provided', async () => {
        const sources: Array<ResourceBrowserSource> = [];

        const { baseElement } = render(<BrowseToSource sources={sources} selectedSource={mockSource()} onSourceSelect={() => {}} />);

        await waitFor(() => {
            const button = baseElement.querySelector(`button[aria-label="Source quick select"]`) as HTMLButtonElement;
            expect(button).toBeFalsy();
        });
    });

    it('Accepts a root className', async () => {
        const sources: Array<ResourceBrowserSource> = [mockSource({ name: 'Source 1' })];

        const { container } = render(
            <BrowseToSource sources={sources} selectedSource={mockSource()} onSourceSelect={() => {}} className="test" />,
        );

        const className = container.querySelector('.test') as HTMLElement;
        expect(className).toBeTruthy();
    });

    it('Sources are rendered when dropdown clicked', async () => {
        const sources = [mockSource({ name: 'Source 1' }), mockSource({ id: '2', name: 'Source 2' })];

        render(<BrowseToSource sources={sources} selectedSource={sources[0]} onSourceSelect={() => {}} />);

        expect(screen.getByRole('button', { name: 'Source quick select' })).toHaveTextContent('Browse');

        const user = userEvent.setup();

        await act(() => user.click(screen.getByRole('button', { name: 'Source quick select' })));

        await waitFor(() => {
            expect(screen.getByRole('button', { name: 'Source quick select' })).toHaveTextContent('Browse to ...');
            expect(screen.getByRole('button', { name: 'dam Source 1 selected' })).toBeTruthy();
            expect(screen.getByRole('button', { name: 'dam Source 2' })).toBeTruthy();
        });
    });

    it('Source menu closes on focus loss', async () => {
        const sources = [mockSource({ name: 'Source 1' }), mockSource({ id: '2', name: 'Source 2' })];

        render(<BrowseToSource sources={sources} selectedSource={sources[0]} onSourceSelect={() => {}} />);

        const user = userEvent.setup();
        const buttonDropdown = screen.getByRole('button', { name: 'Source quick select' });

        await act(() => user.click(buttonDropdown));

        await waitFor(() => {
            expect(screen.queryByRole('button', { name: 'dam Source 1 selected' })).toBeTruthy();
            expect(screen.queryByRole('button', { name: 'dam Source 2' })).toBeTruthy();
        });

        await act(() => fireEvent.blur(buttonDropdown));

        await waitFor(() => {
            expect(screen.queryByRole('button', { name: 'dam Source 1 selected' })).toBeFalsy();
            expect(screen.queryByRole('button', { name: 'dam Source 2' })).toBeFalsy();
        });
    });

    it('Source menu closes on {esc}', async () => {
        const sources = [mockSource({ name: 'Source 1' }), mockSource({ id: '2', name: 'Source 2' })];

        render(<BrowseToSource sources={sources} selectedSource={sources[0]} onSourceSelect={() => {}} />);

        const user = userEvent.setup();
        const buttonDropdown = screen.getByRole('button', { name: 'Source quick select' });

        await act(() => user.click(buttonDropdown));

        await waitFor(() => {
            expect(screen.queryByRole('button', { name: 'dam Source 1 selected' })).toBeTruthy();
            expect(screen.queryByRole('button', { name: 'dam Source 2' })).toBeTruthy();
        });

        await act(() => userEvent.keyboard('{escape}'));

        await waitFor(() => {
            expect(screen.queryByRole('button', { name: 'dam Source 1 selected' })).toBeFalsy();
            expect(screen.queryByRole('button', { name: 'dam Source 2' })).toBeFalsy();
        });
    });

    it('Selecting node calls onSourceSelect ', async () => {
        const onSourceSelect = jest.fn();

        const sources = [mockSource({ name: 'Source 1' }), mockSource({ id: '2', name: 'Source 2' })];

        render(<BrowseToSource sources={sources} selectedSource={sources[0]} onSourceSelect={onSourceSelect} />);

        const user = userEvent.setup();

        await act(() => user.click(screen.getByRole('button', { name: 'Source quick select' })));
        await act(() => user.click(screen.getByRole('button', { name: 'dam Source 2' })));

        await waitFor(() => {
            expect(onSourceSelect).toHaveBeenCalledWith(sources[1]);
        });
    });
});
