import { waitFor } from '@wix/wix-ui-test-utils/unidriver';
import { AddItemUniDriver, CardGalleryItemUniDriver, IconButtonUniDriver, LiveRegionUniDriver, MessageModalLayoutUniDriver, PopoverMenuUniDriver, TextButtonUniDriver, } from '@wix/design-system/dist/testkit/unidriver';
import { CollectionToolbarUniDriver } from '../CollectionToolbar/CollectionToolbar.uni.driver';
import { DragAndDropUniDriver } from '../DragAndDrop/DragAndDrop.uni.driver';
import { CollectionEmptyStateUniDriver } from '../EmptyState/CollectionEmptyState.uni.driver';
import { ToolbarCollectionErrorStateUniDriver } from '../ErrorState/ToolbarCollectionErrorState.uni.driver';
import { ExportButtonUniDriver } from '../ExportButton/ExportButton.uni.driver';
import { ExportModalUniDriver } from '../ExportButton/ExportModal.uni.driver';
import { SkeletonGridUniDriver } from './SkeletonGrid.uni.driver';
import { baseUniDriverFactory, isSled2, isSled3 } from '../../unidriver';
import { SummaryBarUniDriver } from '../SummaryBar/SummaryBar.uni.driver';
import { CollectionPremiumEmptyStateUniDriver } from '../EmptyState/CollectionPremiumEmptyState.uni.driver';
import { CollectionNoResultsStateUniDriver } from '../EmptyState/CollectionNoResultsState.uni.driver';
import { CollectionSectionHeaderUniDriver } from '../CollectionSectionHeader/CollectionSectionHeader.uni.driver';
export function GridUniDriver(base, body) {
    const initialLoaderBase = () => base.$(`[data-hook="grid-initial-loader"]`);
    const initialLoader = () => SkeletonGridUniDriver(initialLoaderBase(), body);
    const infiniteScrollLoaderBase = () => base.$(`[data-hook="infinite-scroll-loader"]`);
    const infiniteScrollLoader = () => SkeletonGridUniDriver(infiniteScrollLoaderBase(), body);
    const slidingModalBase = () => body.$('[data-hook="cairo-side-panel-modal"]');
    const getEmptyStateByDataHook = (dataHook = 'collection-empty-state') => CollectionEmptyStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body);
    const getPremiumEmptyStateByDataHook = (dataHook) => CollectionPremiumEmptyStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body);
    const getNoResultsStateByDataHook = (dataHook = 'collection-empty-state') => CollectionNoResultsStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body);
    const viewsToolbarItem = () => base.$('[data-hook="collection-table-toolbar-views-item"]');
    const getCardGalleryItemByIndexBase = (index) => {
        return base.$(`[data-hook="virtual-grid-item"][data-index="index-${index}"]`);
    };
    const getCardGalleryItemFooterImageByIndexBase = (index) => {
        return base.$(`[data-hook="virtual-grid-item"][data-index="index-${index}"] [data-hook="footer-image"]`);
    };
    const getCardDragElementByIndexBase = (index) => {
        return getCardGalleryItemByIndexBase(index).$('[data-hook="grid-card-item-events"]');
    };
    const getCardGalleryItemByIndex = (index) => {
        const itemDriver = CardGalleryItemUniDriver(getCardGalleryItemByIndexBase(index), body);
        const getPrimaryAction = () => getCardGalleryItemByIndexBase(index).$('[data-hook="primary-action"]');
        return {
            ...itemDriver,
            hoverPrimaryAction: () => getPrimaryAction().hover(),
            isPrimaryActionExists: () => getPrimaryAction().exists(),
        };
    };
    const getAddItem = () => AddItemUniDriver(base.$(`[data-hook="grid-add-item-container"]`), body);
    const getCardGalleryItemPopoverMenuByIndex = async (index) => {
        // Popover isn't active until we specifically call it
        await (await getCardGalleryItemByIndex(index)).getSettingsMenu();
        const popoverBase = base.$$(`[data-hook="popover"]`).get(index);
        const popoverMenu = PopoverMenuUniDriver(popoverBase, body);
        const trigger = popoverBase
            .$$('[data-hook="popover-icon-button-trigger"]')
            .get(0);
        const iconButton = IconButtonUniDriver(trigger, base);
        return {
            ...popoverMenu,
            clickTriggerElement: () => iconButton.click(),
        };
    };
    const getActionModal = () => MessageModalLayoutUniDriver(body.$('[data-hook="collection-action-modal"]'), body);
    const getToolbar = () => CollectionToolbarUniDriver(base.$('[data-hook="collection-toolbar"]'), body);
    const scrollDown = async (scrollableElementDataHook = 'page-scrollable-content') => {
        const scrollableDriver = body.$(`[data-hook="${scrollableElementDataHook}"]`);
        const native = await scrollableDriver.getNative();
        // puppeteer
        if (isSled2(native)) {
            const { page } = native;
            await page.evaluate((_dataHook) => {
                const scrollableElement = document.querySelector(`[data-hook="${_dataHook}"]`);
                scrollableElement.scrollBy({
                    behavior: 'smooth',
                    top: scrollableElement.scrollHeight,
                });
            }, scrollableElementDataHook);
            await page.waitForTimeout(1000); // delay scroll resolve by 1 sec
        }
        // playwright
        else if (isSled3(native)) {
            const locator = (await scrollableDriver.unwrap());
            await locator.evaluate((scrollableElement) => {
                scrollableElement.scrollBy({
                    behavior: 'smooth',
                    top: scrollableElement.scrollHeight,
                });
            });
            await locator.page().waitForTimeout(1000);
        }
        // jsdom
        else {
            if (await scrollableDriver.exists()) {
                await native.dispatchEvent(new Event('scroll'));
            }
        }
    };
    const getDragAndDrop = () => DragAndDropUniDriver(base);
    const getErrorStateByDataHook = (dataHook = 'placeholder-states-error-state') => ToolbarCollectionErrorStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body);
    const refreshLoaderBase = () => base.$(`[data-hook="grid-refresh-loader"]`);
    const refreshLoader = () => SkeletonGridUniDriver(refreshLoaderBase(), body);
    const getNavigationModal = () => MessageModalLayoutUniDriver(body.$('[data-hook="navigation-modal"]'), body);
    const getExportModal = () => ExportModalUniDriver(base, body);
    const getExportButton = () => ExportButtonUniDriver(base.$('[data-hook="export-button"]'), body);
    const getRenderedItemIndexAt = async (i) => {
        const card = base
            .$$('[data-hook="virtual-grid-item"]')
            .filter((e) => e.$('[data-hook="grid-card-item"]').exists())
            .get(i);
        const dataIndexAttr = await card.attr('data-index');
        const index = Number(dataIndexAttr?.replace(/^index-/, ''));
        return Number.isInteger(index) ? index : -1;
    };
    const getLastRenderedItemIndex = async () => {
        const cards = base
            .$$('[data-hook="virtual-grid-item"]')
            .filter((e) => e.$('[data-hook="grid-card-item"]').exists());
        const lastCard = cards.get((await cards.count()) - 1);
        const dataIndexAttr = await lastCard.attr('data-index');
        const index = Number(dataIndexAttr?.replace(/^index-/, ''));
        return Number.isInteger(index) ? index : null;
    };
    const scrollDownToItem = (index, { timeout = 15000, delay = 1000, scrollableElementDataHook = 'page-scrollable-content', scrollIntoView, } = {}) => {
        return waitFor(async () => {
            if (await getCardGalleryItemByIndexBase(index).exists()) {
                if (scrollIntoView) {
                    await getCardGalleryItemByIndexBase(index).scrollIntoView?.();
                }
                return true;
            }
            await scrollDown(scrollableElementDataHook);
            return getCardGalleryItemByIndexBase(index).exists();
        }, timeout, delay);
    };
    const scrollDownToAddItem = ({ timeout = 5000, delay = 1000, scrollableElementDataHook = 'page-scrollable-content', } = {}) => {
        return waitFor(async () => {
            if (await getAddItem().exists()) {
                return true;
            }
            await scrollDown(scrollableElementDataHook);
            return getAddItem().exists();
        }, timeout, delay);
    };
    const _getInnerElement = () => base.$('[data-hook="virtual-inner-element"]');
    const getLiveRegion = () => LiveRegionUniDriver(base.$('[data-hook="collection-live-region"]'), body);
    const getSummaryBar = () => SummaryBarUniDriver(base, body);
    return {
        ...baseUniDriverFactory(base),
        /**
         * Wait until root element to exist
         * @param timeout - time to wait until bailing
         */
        wait: (timeout) => base.wait(timeout),
        /** Wait for the initial fetch loader to be shown */
        waitInitialLoader: (timeout) => initialLoaderBase().wait(timeout),
        /** Wait for the initial fetch loader to be removed */
        waitInitialLoaderRemoved: (timeout) => waitFor(async () => !(await initialLoaderBase().exists()), timeout),
        /** Indicates whether initial loader is in loading status */
        isInitialLoaderLoading: () => initialLoader().exists(),
        /** Indicates whether initial loader exists */
        initialLoaderExists: () => initialLoader().exists(),
        /** Wait for the infinite scroll loader to be shown */
        waitInfiniteScrollLoader: (timeout) => infiniteScrollLoaderBase().wait(timeout),
        infiniteScrollSkeletonCount: () => infiniteScrollLoader().skeletonItemsCount(),
        /** Indicates whether infinite scroll loader exists */
        infiniteScrollLoaderExists: () => infiniteScrollLoader().exists(),
        /** Indicates whether table refresh loader exists */
        refreshLoaderExists: () => refreshLoader().exists(),
        refreshLoaderSkeletonCount: () => refreshLoader().skeletonItemsCount(),
        getErrorStateByDataHook,
        /** Get initial error state before table renders */
        getCardErrorStateByDataHook: (dataHook = 'placeholder-states-error-state') => getErrorStateByDataHook(dataHook),
        /** Get collection empty state within the table that by a specific data hook */
        getEmptyStateByDataHook,
        /** Get premium empty state within the table that by a specific data hook */
        getPremiumEmptyStateByDataHook,
        /** Get collection no results state within the table that by a specific data hook */
        getNoResultsStateByDataHook,
        /** Get the number of actually rendered grid cards */
        getRenderedItemsCount: () => base.$$('[data-hook="grid-card-item"]').count(),
        gridContainerExists: () => _getInnerElement().exists(),
        getVirtualizedRowsCount: async () => {
            const str = await _getInnerElement().attr('data-count');
            return !isNaN(Number(str)) ? Number(str) : 0;
        },
        initialLoaderSkeletonCount: () => infiniteScrollLoader().skeletonItemsCount(),
        /** Get the number rendered grid cards available on the client */
        getLastRenderedItemIndex,
        getLastRenderedItem: async () => {
            const i = await getLastRenderedItemIndex();
            return i != null ? getCardGalleryItemByIndex(i) : null;
        },
        /** Get the CardGalleryItem by index */
        getCardGalleryItemByIndex,
        /** Wait CardGalleryItem by index */
        waitCardGalleryItemByIndex: async (index, timeout) => (await getCardGalleryItemByIndexBase(index)).wait(timeout),
        /** Get the CardGalleryItem's PopoverMenu by index */
        getCardGalleryItemPopoverMenuByIndex,
        getCardDefaultEmptyState: getEmptyStateByDataHook,
        getActionModal,
        /** Get the `<AddItem />` driver for the `renderAddItem` */
        getAddItem,
        getToolbar,
        viewsToolbarItemLabelExists: () => viewsToolbarItem().$('span').exists(),
        getViewsToolbarItemLabelText: () => viewsToolbarItem().$('span').text(),
        /** Get tabs filter driver */
        getToolbarTabs: () => getToolbar().getTabs(),
        /** Enter text into the search input */
        enterSearchText: (text) => getToolbar().enterSearchText(text),
        clearSearchText: () => getToolbar().clearSearchText(),
        getEmptyStateClearFiltersButton: (emptyStateDataHook) => TextButtonUniDriver(base
            .$(`[data-hook="${emptyStateDataHook}"]`)
            .$('[data-hook="empty-state-clear-filters-button"]'), body),
        /**
         * Triggers "scroll" event on the scroll element.
         * @param scrollableElementDataHook - The data hook of the scrollable element (Optional, defaults to "page-scrollable-content").
         */
        scrollDown,
        /**
         * Triggers "scroll" event on the scroll element, until item exists
         * @param index
         * @param timeout - how much to to wait for item exists
         * @param delay - how much to to wait between each check
         * @param scrollableElementDataHook
         */
        scrollDownToItem,
        scrollDownToAddItem,
        scrollToTop: async (scrollableElementDataHook = 'page-scrollable-content') => {
            const pageScrollContent = body.$(`[data-hook="${scrollableElementDataHook}"]`);
            if (await pageScrollContent.exists()) {
                await (await pageScrollContent.getNative()).dispatchEvent(Object.assign(new Event('scroll'), { _testScroll: 'top' }));
            }
        },
        /** @private */
        _getInnerElement,
        getDragHandle: (index) => {
            return getCardGalleryItemByIndexBase(index).$('[data-hook="drag-handle-button"]');
        },
        _getDragAndDropDriver: getDragAndDrop,
        escapeDrag: async (sourceIndex) => getDragAndDrop().escapeDrag((await getCardGalleryItemByIndexBase(sourceIndex)).$(`[data-hook="drag-handle-button"]`)),
        dragStart: async (sourceIndex, options = {}) => getDragAndDrop().dragStart(await getCardDragElementByIndexBase(sourceIndex), options),
        dragStartFromHandleAndKeyboard: async (sourceIndex) => getDragAndDrop().startKeyboardDrag((await getCardGalleryItemByIndexBase(sourceIndex)).$(`[data-hook="drag-handle-button"]`)),
        dragStartFromHandle: async (sourceIndex) => getDragAndDrop().dragStart((await getCardGalleryItemByIndexBase(sourceIndex)).$(`[data-hook="drag-handle-button"]`)),
        dragMove: () => getDragAndDrop().dragMove(),
        dragEnd: async (targetIndex) => getDragAndDrop().dragEnd(await getCardDragElementByIndexBase(targetIndex)),
        /**
         * Drags an element over another element.
         * @param {number} sourceIndex
         * @param {number} targetIndex
         * @param [options]
         * @param {number} [options.steps] number of movement steps (only for puppeteer)
         */
        dragOver: async (sourceIndex, targetIndex, options = {}) => {
            return getDragAndDrop().dragOver(await getCardDragElementByIndexBase(sourceIndex), await getCardDragElementByIndexBase(targetIndex), options);
        },
        getNavigationModal,
        getLiveRegionText: async () => (await getLiveRegion()).getMessage(),
        getLiveRegionRole: async () => (await getLiveRegion()).getRole(),
        getDragAndDropLiveRegionText: () => body.$('[data-hook="grid-dnd-live-region"]').text(),
        _getCardDragElementByIndexBase: getCardDragElementByIndexBase,
        _getCardGalleryItemByIndexBase: getCardGalleryItemByIndexBase,
        waitSidePanelFullyOpened: () => {
            return waitFor(async () => (await slidingModalBase().attr('data-transition-status')) ===
                'entered');
        },
        /** Get an export button driver **/
        getExportButton,
        /** Get an export modal driver **/
        getExportModal,
        /** Is 'ExportTo' modal open */
        isExportModalOpen: () => getExportButton().getModal().isOpen(),
        getCardGalleryItemFooterImageByIndexBase,
        getRenderedItemIndexAt,
        getDragOverlayCardGalleryItem: () => CardGalleryItemUniDriver(body.$('[data-hook="draggable-card-overlay"]'), body),
        internalScrollDownToItem: (index, options = {}) => scrollDownToItem(index, {
            ...options,
            scrollableElementDataHook: 'toolbar-collection-content-auto-sizer',
        }),
        /**
         * Gets collection summary bar
         */
        getSummaryBar,
        getSectionHeaderAt: (index) => CollectionSectionHeaderUniDriver(base.$$('[data-hook="grid-section-header"]').get(index), body),
        getSectionHeadersCount: () => base.$$('[data-hook="grid-section-header"]').count(),
        getSectionGridAt: (index) => GridUniDriver(base.$$('[data-hook="grid-section-and-repeater"]').get(index), body),
    };
}
export default GridUniDriver;
//# sourceMappingURL=Grid.uni.driver.js.map