import { fireEvent, screen, waitFor } from '@testing-library/react';

interface Option {
    label: string;
}

export const openSelect = async (testId = 'SuiteSelect') => {
    const select = screen.getByTestId(testId);
    const input = getInput();
    fireEvent.click(input);

    await screen.findByTestId('SuiteListView');
    return select;
};

export const openMultiSelect = async (testId = 'SuiteMultiSelect') => {
    return await openSelect(testId);
};

export const querySelectMenu = () => {
    return screen.queryByTestId('SuiteListView');
};

export const getInput = () => {
    return screen.getByRole('combobox', { hidden: true }) as HTMLInputElement;
};

export const getInputWrapper = () => {
    return screen.getByTestId('SuiteSelectInput');
};

export const getInputDisplayValue = () => {
    return getInputWrapper().querySelector('.TruncatedText-inner')?.textContent;
};

export const getInputDisplayValues = () => {
    return Array.from(
        screen
            .getByTestId('SuiteSelectInputMultiValueTagsContainer')
            .querySelectorAll('.TruncatedText-inner')
    ).map((element) => element.textContent);
};

export const getInputValue = () => {
    return getInput().value;
};

export const findOption = async (option: Option) => {
    const element = await screen.findByText(option.label!, {
        selector: '.SuiteListView .SuiteListView-option-label',
    });

    return element.closest('.SuiteListView-option')!;
};

export const getOption = (option: Option) => {
    const element = screen.getByText(option.label!, {
        selector: '.SuiteListView .SuiteListView-option-label',
    });

    return element.closest('.SuiteListView-option')!;
};

export const getListTag = (option: Option) => {
    return screen
        .getByText(option.label!, {
            selector: '.SuiteListView .TagCloud-tag .TruncatedText-inner',
        })
        .closest('.TagCloud-tag')!;
};

export const getInputTag = (option: Option) => {
    return screen
        .getByText(option.label!, {
            selector: '.SuiteSelect-input .SuiteSelect-input-multi-value-tag .TruncatedText-inner',
        })
        .closest('.SuiteSelect-input-multi-value-tag')!;
};

export const findInputTag = async (option: Option) => {
    return (
        await screen.findByText(option.label!, {
            selector: '.SuiteSelect-input .SuiteSelect-input-multi-value-tag .TruncatedText-inner',
        })
    ).closest('.SuiteSelect-input-multi-value-tag')!;
};

export const findOptionTag = async (option: Option) => {
    return (
        await screen.findByText(option.label!, {
            selector: '.TagCloud-tag .TruncatedText-inner',
        })
    ).closest('.TagCloud-tag')!;
};

export const queryListTag = (option: Option) => {
    return (
        screen
            .queryByText(option.label!, {
                selector: '.SuiteListView .TagCloud-tag .TruncatedText-inner',
            })
            ?.closest('.TagCloud-tag') ?? null
    );
};

export const queryInputTag = (option: Option) => {
    return (
        screen
            .queryByText(option.label!, {
                selector:
                    '.SuiteSelect-input .SuiteSelect-input-multi-value-tag .TruncatedText-inner',
            })
            ?.closest('.SuiteSelect-input-multi-value-tag') ?? null
    );
};

export const getGroup = (option: Option) => {
    const element = screen.getByText(option.label, {
        selector: '.SuiteListView .SuiteListView-group-label',
    });

    return element.closest('.SuiteListView-group')!;
};

export const getSectionHeader = (option: Option) => {
    return screen.getByText(option.label, {
        selector: '.SuiteListView .SuiteListView-section-header',
    });
};

export const queryOption = (option: Option) => {
    const element = screen.queryByText(option.label!, {
        selector: '.SuiteListView .SuiteListView-option-label',
    });

    return element?.closest('.SuiteListView-option') ?? null;
};

export const getFilterInput = () => {
    return screen.getByTestId('SuiteListViewFilterInput');
};

export const triggerFilterChange = (value?: string) => {
    fireEvent.change(getFilterInput(), { target: { value } });
};

export const triggerFilterKeyDown = (key: string) => {
    fireEvent.keyDown(getFilterInput(), { key });
};

export const triggerInputKeyDown = (key: string) => {
    fireEvent.keyDown(getInput(), { key });
};

export const clickApplyButton = () => {
    const button = screen.getByText('Apply');
    fireEvent.click(button);
};

export const selectOption = (option: Option) => {
    const row = getOption(option);
    fireEvent.click(row);
    return row;
};

export const waitForOptionToBeHighlighted = async (option: Option) => {
    await waitFor(async () => {
        const element = await findOption(option);

        if (!element.classList.contains('highlight'))
            throw new Error('Option does not have the "highlight" class');
    });
};

export const getListOptions = (list: HTMLElement) => {
    return list.getElementsByClassName('SuiteListView-option');
};
