import { getByRole, fireEvent, waitFor } from '@testing-library/react';
import { renderComponent } from 'lib/test-helpers/render-helper';
import { createCollaboratorSearchQueryMock } from 'src/queries/collaborator-search';
import { CollaboratorType } from 'src/__definitions__/globalTypes';

import { Option as SelectOption } from 'react-select/src/filters';
import { Collaborator } from 'src/types/SplitEditState';
import CollaboratorDropdown from '../collaborator-dropdown';

const mocks = [
    createCollaboratorSearchQueryMock(
        { searchTerm: 'hello' },
        {
            collaboratorSearch: {
                __typename: 'CollaboratorResults',
                collaborators: [
                    {
                        __typename: 'Collaborator',
                        name: 'Collab 1234',
                        id: 1234,
                        collaboratorType: CollaboratorType.COLLABORATOR,
                        subaccountId: 1234
                    }
                ],
            },
        }
    ),
];

interface Fixture {
    splitEdit: { level: 'PRODUCT' | 'TRACK' }
    productSplits: Array<{ collaborator: { id: number }, isProrated: boolean }>
    splits: Array<{ collaborator: { id: number } }>
    optionExpectedInDropdown: boolean
}

const fixtures: Fixture[] = [
    {
        // Editing at product level, NO splits
        splitEdit: { level: 'PRODUCT' },
        productSplits: [],
        splits: [],
        optionExpectedInDropdown: true,
    },
    {
        // Editing at product level, splits, NOT prorated
        splitEdit: { level: 'PRODUCT' },
        productSplits: [{ collaborator: { id: 1234 }, isProrated: false }],
        splits: [],
        optionExpectedInDropdown: false,
    },
    {
        // Editing at track level, NOT prorated
        splitEdit: { level: 'TRACK' },
        productSplits: [{ collaborator: { id: 1234 }, isProrated: false }],
        splits: [],
        optionExpectedInDropdown: false,
    },
    {
        // Editing at track level, prorated, existing track splits
        splitEdit: { level: 'TRACK' },
        productSplits: [{ collaborator: { id: 1234 }, isProrated: true }],
        splits: [{ collaborator: { id: 1234 } }],
        optionExpectedInDropdown: false,
    },
    {
        // Editing at track level, prorated, NO exisiting track splits
        splitEdit: { level: 'TRACK' },
        productSplits: [{ collaborator: { id: 1234 }, isProrated: true }],
        splits: [],
        optionExpectedInDropdown: true,
    }
];

function createFilterOption({ productSplits, splitEdit, splits }: typeof fixtures[0]) {
    return (option: SelectOption): boolean => {
        if (option.value === 'add-new') return true;
        const collab = option.data as Collaborator;
        const productLevelSplit = productSplits.find((split) => split.collaborator.id === collab.id);
        if (productLevelSplit) {
            if (splitEdit?.level === 'PRODUCT' || !productLevelSplit.isProrated) return false;
            const trackLevelSplit = splits.find((split) => split.collaborator.id === collab.id);
            return !trackLevelSplit;
        }
        return true;
    };
}

describe('<CollaboratorDropdown>', () => {
    describe('filtering dropdown options with the filterOption field', () => {

        const doFilterOptionTest = async (fixture: Fixture) => {
            const component = renderComponent({
                Component: CollaboratorDropdown,
                mocks,
                props: {
                    filterOption: createFilterOption(fixture)
                }
            });

            const collaboratorSelect = component.getByText('messages.searchCollaborator').closest('.Select') as HTMLElement;
            const collaboratorSelectInput = getByRole(collaboratorSelect, 'textbox');
            fireEvent.change(collaboratorSelectInput, { target: { value: 'hello' } });

            await waitFor(() => {
                expect(collaboratorSelect.querySelector('.Select__loading-indicator')).toBeFalsy();
            });

            if (fixture.optionExpectedInDropdown)
                expect(component.queryByText('Collab 1234')).toBeInTheDocument();
            else
                expect(component.queryByText('Collab 1234')).not.toBeInTheDocument();
        };

        describe('When editing at the product level', () => {
            test('When there are NO splits the collaborator appears in the dropdown', () =>
                doFilterOptionTest(fixtures[0]));

            test('When there are splits at any level, the collaborator does NOT appear in the dropdown', () =>
                doFilterOptionTest(fixtures[1]));
        });

        describe('When editing at the track level', () => {
            test('When the product is NOT prorated, the collaborator does NOT appear in the dropdown', () =>
                doFilterOptionTest(fixtures[2]));

            describe('When the product is prorated', () => {
                test('When the collaborator already has a track level split, it does NOT appear in the dropdown', () =>
                    doFilterOptionTest(fixtures[3]));

                test('When the collaborator does NOT already have a track level split, it appears in the dropdown', () =>
                    doFilterOptionTest(fixtures[4]));
            });
        });
    });
});
