import { UniDriver, waitFor } from '@wix/wix-ui-test-utils/unidriver';
import { baseUniDriverFactory } from '../../unidriver';
import {
  EmptyStateUniDriver,
  FloatingNotificationUniDriver,
  SelectorListUniDriver,
  SelectorUniDriver,
} from '@wix/design-system/dist/testkit/unidriver';
import { PickerTableListItemUniDriver } from '../PickerTableListItem/PickerTableListItem.uni.driver';

export function PickerUniDriver(base: UniDriver, body: UniDriver) {
  const selectorList = SelectorListUniDriver(base, body);

  const getEmptyState = async <T, E>(factory: (element: E) => T) =>
    factory(await base.getNative());

  const getSelectors = () =>
    base
      .$('[data-hook="selector-list-content"]')
      .$$('[data-hook="selector-list-selector"]');

  const selectorDriverAt = (i: number) =>
    SelectorUniDriver(getSelectors().get(i), body);

  const tableListItemDriverAt = (i: number) =>
    PickerTableListItemUniDriver(getSelectors().get(i), body);

  const getSearchLoader = () => base.$('[data-hook="search-loader"]');

  const getFloatingNotification = () =>
    FloatingNotificationUniDriver(
      base.$('[data-hook="floating-notification"]'),
      body,
    );

  const getPrimaryActionButtonAt = (i: number) =>
    getSelectors().get(i).$('[data-hook="primary-action-button"]');

  return {
    ...baseUniDriverFactory(base),
    wait: (timeout?: number) => base.wait(timeout),
    waitSearchLoader: (timeout?: number) => getSearchLoader().wait(timeout),
    searchLoaderExists: () => getSearchLoader().exists(),
    waitSearchLoaderRemoved: (timeout?: number) =>
      waitFor(async () => !(await getSearchLoader().exists()), timeout),
    numberOfItemsInList: () => getSelectors().count(),
    primaryButtonExistsAt: (i: number) => getPrimaryActionButtonAt(i).exists(),
    getPrimaryActionButtonAt,
    scrollDown: async () => {
      const element = await base.getNative();

      const { page } = element;

      // puppeteer
      if (page?.evaluate) {
        await page.evaluate(() => {
          const e = document.querySelector(
            '[data-hook="selector-list-content"]',
          )!;
          e.scrollBy({ behavior: 'smooth', top: e.scrollHeight });
        });
      } else {
        await selectorList.scrollDown();
      }
    },
    scrollTo: (i: number) => getSelectors().get(i).scrollIntoView?.(),
    toggleSelectorAt: selectorList.toggleSelectorAt,
    getTotalSelected: async () => {
      const checked = await Promise.all(
        await getSelectors().map((selector) =>
          SelectorUniDriver(selector, body).isChecked(),
        ),
      );

      return checked.filter(Boolean).length;
    },
    isSelectorCheckedAt: selectorList.isSelectorCheckedAt,
    isListItemDisabledAt: (i: number) => selectorDriverAt(i).isDisabled(),
    waitListItemAt: async (i: number, timeout?: number) =>
      waitFor(() => selectorDriverAt(i).exists(), timeout),
    getTableListItemAt: (i: number) => tableListItemDriverAt(i),
    waitRowEntered: (i: number, timeout?: number) =>
      base
        .$('[data-hook="selector-list-content"]')
        .$$('[data-hook="picker-list-fade-item"].fade-entered')
        .get(i)
        .wait(timeout),
    hoverItemAt: (i: number) => getSelectors().get(i).hover(),
    getTitleTextAt: async (i: number) =>
      selectorDriverAt(i).titleTextDriver().getText(),
    isIndeterminateAt: async (i: number) =>
      selectorDriverAt(i).isIndeterminate(),
    getTitleTextContentAt: async (i: number) =>
      getSelectors().get(i).$('[data-hook="selector-title"]').text(),
    getSubtitleTextAt: async (i: number) =>
      selectorDriverAt(i).subtitleTextDriver().getText(),
    getSubtitleTextContentAt: async (i: number) =>
      getSelectors().get(i).$('[data-hook="selector-subtitle"]').text(),
    getExtraNodeElementAt: (i: number) => selectorDriverAt(i).getExtraNode(),
    getImageElementAt: (i: number) => selectorDriverAt(i).getImage(),
    getToggleTooltipTextAt: (i: number) => selectorDriverAt(i).getTooltipText(),
    floatingNotificationExists: () => getFloatingNotification().exists(),
    getFloatingNotificationText: () => getFloatingNotification().getText(),
    getEmptyState,
    getEmptyStateByDataHook: (dataHook = 'picker-empty-state') =>
      EmptyStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body),
    getErrorStateByDataHook: (dataHook: string) =>
      EmptyStateUniDriver(base.$(`[data-hook="${dataHook}"]`), body),
  };
}
