import { UniDriver } from '@wix/wix-ui-test-utils/unidriver';
import { CollectionToolbarUniDriver } from '../CollectionToolbar/CollectionToolbar.uni.driver';
import { baseUniDriverFactory } from '../../unidriver/baseUniDriverFactory';
import { SledPage } from '@wix/sled-test-runner';
import {
  AddItemUniDriver,
  BoxUniDriver,
  ButtonUniDriver,
  CounterBadgeUniDriver,
  IconButtonUniDriver,
  MessageModalLayoutUniDriver,
  PopoverMenuUniDriver,
  TextUniDriver,
  TooltipUniDriver,
} from '@wix/design-system/dist/testkit/unidriver';
import { DragAndDropUniDriver } from '../DragAndDrop/DragAndDrop.uni.driver';
import { ManageTagsModalUniDriver } from '../Tags/ManageTags/ManageTagsModal/ManageTagsModal.uni.driver';
import { CustomFieldPanelUniDriver } from '../CustomFieldsPanel/CustomFieldPanel.uni.driver';

export function KanbanUniDriver(base: UniDriver, body: UniDriver) {
  const toolbarBase = () => base.$('[data-hook="collection-toolbar"]');

  const toolbar = () => CollectionToolbarUniDriver(toolbarBase(), body);

  const dragAndDrop = () => DragAndDropUniDriver(base);

  const dragCardToStage = async ({
    sourceStageKey,
    cardKey,
    targetStageKey,
  }: {
    sourceStageKey: string;
    cardKey: string;
    targetStageKey: string;
  }) => {
    const targetStageElement = base.$(
      `[data-hook^="kanban-stage-container-${targetStageKey}"]`,
    );

    if (!(await targetStageElement.exists())) {
      throw new Error(`Target stage with key ${targetStageKey} not found`);
    }

    const sourceStageElement = base.$(
      `[data-hook^="kanban-stage-container-${sourceStageKey}"]`,
    );

    if (!(await sourceStageElement.exists())) {
      throw new Error(`Source stage with key ${sourceStageKey} not found`);
    }

    const cardElement = base.$(
      `[data-hook^="kanban-card-drag-item-${sourceStageKey}-##-${cardKey}"]`,
    );

    if (!(await cardElement.exists())) {
      throw new Error(
        `Card with key ${cardKey} not found in stage ${sourceStageKey}`,
      );
    }

    const driverDragAndDrop = dragAndDrop();
    await driverDragAndDrop.dragStart(cardElement);
    await driverDragAndDrop.dragEnd(targetStageElement);
  };

  return {
    ...baseUniDriverFactory(base),
    toolbar: () => toolbar(),
    enterSearchText: (text: string) => toolbar().enterSearchText(text),
    clearSearchText: () => toolbar().clearSearchText(),
    isKanbanLoading: () =>
      base.$('[data-hook="kanban-stages-skeleton"]').exists(),
    getCustomFieldPanel: () => CustomFieldPanelUniDriver(body, body),
    getManageTagsModal: () => ManageTagsModalUniDriver(base, body),
    stages: {
      count: () => base.$$('[data-hook^="kanban-stage-container"]').count(),
      doneDividerExists: async () => {
        const count = await base
          .$$(`[data-hook^="kanban-stages-done-divider"]`)
          .count();
        return count > 0;
      },
      stageTitle: (stageId: string) => {
        return TextUniDriver(
          base.$(`[data-hook^="kanban-stage-title-${stageId}"]`),
          body,
        );
      },
      stageSummary: (stageId: string) => {
        const counterBadge = CounterBadgeUniDriver(
          base.$(`[data-hook^="kanban-stage-title-total-${stageId}"]`),
          body,
        );
        return {
          ...counterBadge,
          exists: () => counterBadge.exists(),
          totalItems: () => counterBadge.getContentText(),
        };
      },
      scrollToEndOfStageCardsContainer: async (stageKey: string) => {
        const scrollableElementDataHook = `kanban-stage-cards-container-${stageKey}`;

        const { page } = (await body
          .$(`[data-hook="${scrollableElementDataHook}"]`)
          .getNative()) as {
          page?: SledPage['page'];
        };
        // puppeteer
        if (page?.evaluate) {
          await page.evaluate((_dataHook: string) => {
            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
        }
        // jsdom
        else {
          const pageScrollContent = body.$(
            `[data-hook="${scrollableElementDataHook}"]`,
          );

          if (await pageScrollContent.exists()) {
            // Scroll to the end of pageScrollContent by setting scrollTop to (scrollHeight - clientHeight)
            const nativeEl = await pageScrollContent.getNative();
            nativeEl.scrollTop = nativeEl.scrollHeight - nativeEl.clientHeight;
            await nativeEl.dispatchEvent(new Event('scroll'));
          }
        }
      },
      stageSummaryBadge: (stageId: string) => {
        const counterBadge = CounterBadgeUniDriver(
          base.$(`[data-hook^="kanban-stage-title-total-${stageId}"]`),
          body,
        );
        return {
          ...counterBadge,
          exists: () => counterBadge.exists(),
          totalItems: () => counterBadge.getContentText(),
        };
      },
      addCardButton: (stageKey: string) =>
        AddItemUniDriver(
          base.$(`[data-hook="kanban-stage-add-card-${stageKey}"]`),
          body,
        ),
      stagesSkeleton: () =>
        BoxUniDriver(base.$('[data-hook="kanban-stages-skeleton"]'), body),
      noResultsBox: (stageKey: string) =>
        BoxUniDriver(
          base.$(`[data-hook="kanban-stage-no-results-${stageKey}"]`),
          body,
        ),
      cardsSkeleton: (stageKey: string) =>
        BoxUniDriver(
          base.$(`[data-hook="kanban-cards-skeleton-${stageKey}"]`),
          body,
        ),
    },
    cards: {
      count: (stageKey: string) =>
        base.$$(`[data-hook^="kanban-card-${stageKey}-"]`).count(),
      exists: ({ stageKey, cardKey }: { stageKey: string; cardKey: string }) =>
        base.$(`[data-hook^="kanban-card-${stageKey}-${cardKey}"]`).exists(),
      getTitle: ({
        stageKey,
        cardKey,
      }: {
        stageKey: string;
        cardKey: string;
      }) => {
        return TextUniDriver(
          base.$(`[data-hook^="kanban-card-title-${stageKey}-${cardKey}"]`),
          body,
        );
      },
      getPrimaryAction: ({
        stageKey,
        cardKey,
      }: {
        stageKey: string;
        cardKey: string;
      }) => {
        const tooltip = TooltipUniDriver(
          base.$(
            `[data-hook="kanban-card-primary-action-tooltip-${stageKey}-${cardKey}"]`,
          ),
          body,
        );
        const button = ButtonUniDriver(
          base.$(
            `[data-hook="kanban-card-primary-action-${stageKey}-${cardKey}"]`,
          ),
          body,
        );
        return {
          ...button,
          exists: () => button.exists(),
          text: () => button.getButtonTextContent(),
          tooltip: () => tooltip,
        };
      },
      getSecondaryActions: ({
        stageKey,
        cardKey,
      }: {
        stageKey: string;
        cardKey: string;
      }) => {
        const popoverMenu = PopoverMenuUniDriver(
          base.$(
            `[data-hook="kanban-card-more-actions-${stageKey}-${cardKey}"]`,
          ),
          body,
        );

        const triggerButton = popoverMenu.getTriggerElement(
          `kanban-card-more-actions-trigger-${stageKey}-${cardKey}`,
        );
        const iconButton = IconButtonUniDriver(triggerButton, base);
        return {
          ...popoverMenu,
          clickTriggerElement: () => iconButton.click(),
        };
      },
      getActionModal: () =>
        MessageModalLayoutUniDriver(
          body.$('[data-hook="collection-action-modal"]'),
          body,
        ),
      dragCardToStage,
    },
  };
}

export default KanbanUniDriver;
