import { UniDriver, waitFor } from '@wix/wix-ui-test-utils/unidriver';
import {
  AddItemUniDriver,
  MessageModalLayoutUniDriver,
} from '@wix/design-system/dist/testkit/unidriver';
import { baseUniDriverFactory } from '../../unidriver';
import { EditableCellUniDriver } from './EditableCell.uni.driver';
import { EditableTableContextMenuUniDriver } from './EditableTableContextMenu.uni.driver';
import { EditableColumnHeaderUniDriver } from './EditableColumnHeader.uni.driver';

const { fireEvent = null } =
  process.env.NODE_ENV === 'test'
    ? (() => {
        try {
          return require('@testing-library/react');
        } catch {}
        return {};
      })()
    : {};

export function EditableTableUniDriver(base: UniDriver, body: UniDriver) {
  const getRows = () => base.$$('tbody tr[data-table-row="dataTableRow"]');

  const getCells = () => base.$$('[role="gridcell"]');

  const initialLoaderBase = () =>
    base.$('[data-hook="placeholder-states-loading-state"]');

  return {
    ...baseUniDriverFactory(base),

    /** Number of rendered data rows */
    getRowsCount: () => getRows().count(),

    /** Number of column headers */
    getColumnsCount: () => base.$$('thead th').count(),

    /** Get column header texts */
    getColumnHeaders: () => base.$$('thead th').map((th) => th.text()),

    /** Get a cell driver by row key and column id */
    getCell: (rowKey: string, columnId: string) =>
      EditableCellUniDriver(
        base.$(
          `[role="gridcell"][data-row-key="${rowKey}"][data-column-id="${columnId}"]`,
        ),
        body,
      ),

    /** Get a cell driver by row index and column index */
    getCellByIndex: (rowIdx: number, colIdx: number) => {
      const row = getRows().get(rowIdx);
      const cell = row.$$('[role="gridcell"]').get(colIdx);
      return EditableCellUniDriver(cell, body);
    },

    /** Total number of gridcells rendered */
    getCellsCount: () => getCells().count(),

    /** Wait until root element exists */
    wait: (timeout?: number) => base.wait(timeout),

    /** Wait for the initial fetch loader to be shown */
    waitInitialLoader: (timeout?: number) => initialLoaderBase().wait(timeout),

    /** Wait for the initial fetch loader to be removed */
    waitInitialLoaderRemoved: (timeout?: number, delay?: number) =>
      waitFor(
        async () => !(await initialLoaderBase().exists()),
        timeout,
        delay,
      ),

    /** Wait for at least one data row to render */
    waitForRow: (timeout?: number) => getRows().get(0).wait(timeout),

    /** Get the header actions driver for a column (portaled to body) */
    getHeaderActions: (columnId: string) =>
      EditableColumnHeaderUniDriver(
        base.$(`[data-hook="header-actions-${columnId}"]`),
        body,
      ),

    /** Get the context menu driver (portaled to body) */
    getContextMenu: () => EditableTableContextMenuUniDriver(base, body),

    /** Get the add item row driver */
    getAddItemRow: () =>
      AddItemUniDriver(base.$('[data-hook="add-row-button"]'), body),

    /** Get the delete confirmation modal driver */
    getConfirmActionModal: () =>
      MessageModalLayoutUniDriver(
        body.$('[data-hook="collection-action-modal"]'),
        body,
      ),

    /** Press a key on the table container (triggers useKeyboardNavigation) */
    pressKey: async (key: string, opts?: Record<string, unknown>) => {
      const el = await base.getNative();
      if (fireEvent) {
        fireEvent.keyDown(el, { key, ...opts });
      } else {
        el.dispatchEvent(
          new KeyboardEvent('keydown', { key, bubbles: true, ...opts }),
        );
      }
    },

    /** Dispatch a paste event on the table container */
    dispatchPaste: async (text: string) => {
      const el = await base.getNative();
      const event = Object.assign(new Event('paste', { bubbles: true }), {
        clipboardData: { getData: () => text },
      });
      el.dispatchEvent(event);
    },
  };
}

export default EditableTableUniDriver;
