import {
    act,
    fireEvent,
    render,
    screen,
    waitFor,
} from '@testing-library/react';
import React from 'react';
import DeliveryStoreSelect from '../delivery-store-select';
import type { DeliveryStoreSelectProps } from '../delivery-store-select';

const deliveryStores = [
    {
        id: '826',
        name: 'Spotify',
    },
    {
        id: '712',
        name: 'Apple',
    },
    {
        id: '956',
        name: 'Amazon',
    },
];

const selected = [
    {
        id: '826',
        name: 'Spotify',
    },
];

const disabled = [
    {
        id: '712',
        name: 'Apple',
    },
];

const carvedOutStores = [
    {
        id: '956',
        name: 'Amazon',
    },
];

const title = 'Store Select';

describe('<DeliveryStoreSelect>', () => {
    const onSelect = jest.fn();
    const defaultProps = {
        title,
        onSelect,
        selected,
        deliveryStores,
        carvedOutStores: [],
    };

    beforeEach(() => {
        const mockIntersectionObserver = jest.fn();
        mockIntersectionObserver.mockReturnValue({
            observe: () => null,
            unobserve: () => null,
            disconnect: () => null,
        });
        window.IntersectionObserver = mockIntersectionObserver;
    });

    const renderComponent = (props: Partial<DeliveryStoreSelectProps> = {}) =>
        render(<DeliveryStoreSelect {...defaultProps} {...props} />);

    afterEach(jest.resetAllMocks);

    describe('title', () => {
        test('renders', () => {
            const { queryByText } = renderComponent();
            const columnTitle = queryByText(title);
            expect(columnTitle).toBeInTheDocument();
        });
    });

    describe('select all', () => {
        test('calls onSelect with all delivery stores', () => {
            const { container } = renderComponent();
            const columnHeaders = container.getElementsByClassName(
                'GridTable-header-row'
            )[0];
            const selectAll = columnHeaders.getElementsByTagName('input')[0];
            fireEvent.click(selectAll);
            expect(onSelect).toHaveBeenCalledWith(deliveryStores);
        });
    });

    describe('selecting a delivery store', () => {
        describe('calls onSelect with value matching delivery store', () => {
            test('select store clicking checkbox', () => {
                const { container } = renderComponent({ selected: [] });
                const tableBody =
                    container.getElementsByClassName('GridTable-body')[0];
                const checkboxCell = tableBody.getElementsByClassName(
                    'cell-table-selection'
                )[0];
                const select = checkboxCell.getElementsByTagName('input')[0];
                fireEvent.click(select);
                expect(onSelect).toHaveBeenCalledWith([deliveryStores[0]]);
            });

            test('select store clicking on store name', () => {
                const { container } = renderComponent({ selected: [] });
                const tableBody =
                    container.getElementsByClassName('GridTable-body')[0];
                const tableRow =
                    tableBody.getElementsByClassName('GridTable-row')[0];
                fireEvent.click(tableRow);
                expect(onSelect).toHaveBeenCalledWith([deliveryStores[0]]);
            });
        });
    });

    describe('unable to select already selected store', () => {
        test('already selected store checkbox is disabled', () => {
            const { container } = renderComponent({
                disabledStores: disabled,
                selected: [],
            });
            const tableBody =
                container.getElementsByClassName('GridTable-body')[0];
            const checkboxCell = tableBody.getElementsByClassName(
                'cell-table-selection'
            )[1];
            const select = checkboxCell.getElementsByTagName('input')[0];
            expect(select).toBeDisabled();
        });

        test('clicking on disabled row does not call onSelect', () => {
            const notOnSelect = jest.fn();
            const { container } = renderComponent({
                disabledStores: disabled,
                selected: [],
                onSelect: notOnSelect,
            });
            const tableBody =
                container.getElementsByClassName('GridTable-body')[0];
            const tableRow =
                tableBody.getElementsByClassName('GridTable-row')[1];
            fireEvent.click(tableRow);
            expect(notOnSelect).not.toHaveBeenCalled();
        });
    });

    describe('disabled tooltip', () => {
        test('store is disabled and tooltip is rendered', async () => {
            const disabledTooltip = 'Store already scheduled';
            const carvedOutTooltip = 'Store carved out';
            const { container, getByTestId } = renderComponent({
                disabledStores: disabled,
                disabledTooltip,
                carvedOutStores: [],
                carvedOutTooltip,
                selected: [],
            });
            const tableRow =
                container.getElementsByClassName('GridTable-row')[2];
            const trigger = getByTestId('tooltip-trigger');

            await act(async () => {
                await fireEvent.mouseOver(trigger);
            });

            await waitFor(async () => await screen.findByText(disabledTooltip));
            const tooltip = tableRow.getElementsByClassName('tooltip')[0];
            expect(trigger.innerHTML).toBe('Apple');
            expect(tooltip).toBeInTheDocument();
        });
    });

    describe('carved out tooltip', () => {
        test('store is carved out and tooltip is rendered', async () => {
            const disabledTooltip = 'Store already scheduled';
            const carvedOutTooltip = 'Store carved out';
            const { container, getByTestId } = renderComponent({
                disabledStores: [],
                disabledTooltip,
                carvedOutStores,
                carvedOutTooltip,
                selected: [],
            });
            const tableRow =
                container.getElementsByClassName('GridTable-row')[3];
            const trigger = getByTestId('tooltip-trigger');

            await act(async () => {
                await fireEvent.mouseOver(trigger);
            });

            await waitFor(
                async () => await screen.findByText(carvedOutTooltip)
            );
            const tooltip = tableRow.getElementsByClassName('tooltip')[0];
            expect(trigger.innerHTML).toBe('Amazon');
            expect(tooltip).toBeInTheDocument();
        });
    });
});
