import type { UniDriver } from '@wix/wix-ui-test-utils/unidriver';
import {
  DropdownUniDriver,
  ListItemSectionUniDriver,
} from '@wix/design-system/dist/testkit/unidriver';
import { baseUniDriverFactory } from '../../unidriver';
import { ViewsDropdownListItemUniDriver } from './ViewsDropdownListItem.uni.driver';
import { ManageViewPopoverUniDriver } from './ManageViewPopover.uni.driver';
import { CollectionSaveViewModalUniDriver } from './modals/SaveView/CollectionSaveViewModal.uni.driver';
import { CollectionRenameViewModalUniDriver } from './modals/RenameView/CollectionRenameViewModal.uni.driver';
import { SaveToNewViewFooterUniDriver } from './SaveToNewViewFooter.uni.driver';

export const CollectionViewsDropdownUniDriver = (
  base: UniDriver,
  body: UniDriver,
) => {
  const viewsDropdownDriverBase = () =>
    base.$('[data-hook="collection-views-dropdown"]');

  // In redesign mode the manage view popover (3-dots menu) is rendered inside
  // the dropdown list as a suffix on the selected view item. The dropdown
  // content is rendered in a portal, so we search `body` instead of `base`.
  // In legacy mode the popover is next to the dropdown inside `base`, but
  // searching `body` still finds it because `base` is within `body`.
  const manageViewPopover = () => ManageViewPopoverUniDriver(body, body);
  const getSaveViewModal = () => CollectionSaveViewModalUniDriver(base, body);
  const getRenameViewModal = () =>
    CollectionRenameViewModalUniDriver(base, body);
  const saveToNewViewFooter = () => SaveToNewViewFooterUniDriver(body, body);

  const getDropdownLayoutBase = async () => {
    const contentDataHook = await viewsDropdownDriverBase().attr(
      'data-content-hook',
    );

    if (contentDataHook) {
      return body.$(`[data-content-element="${contentDataHook}"]`);
    }

    const baseDataHook = await viewsDropdownDriverBase().attr('data-hook');

    return body.$(`[data-hook="${baseDataHook}-content"]`);
  };

  const viewsDropdownDriver = () =>
    DropdownUniDriver(viewsDropdownDriverBase(), body);

  const getViewListItemById = (id: string) => {
    return ViewsDropdownListItemUniDriver(
      viewsDropdownDriverBase().$(`[data-hook="dropdown-item-${id}"]`),
      body,
    );
  };

  const getViewListItemAt = (index: number) => {
    return ViewsDropdownListItemUniDriver(
      viewsDropdownDriverBase().$$('[data-hook="view-item"]').get(index),
      body,
    );
  };

  const getCategoryListItemById = (id: string) => {
    return ListItemSectionUniDriver(
      viewsDropdownDriverBase().$(`[data-hook="dropdown-item-${id}"]`),
      body,
    );
  };

  const getCategoryListItemAt = (index: number) => {
    return ListItemSectionUniDriver(
      viewsDropdownDriverBase().$$('[data-hook="view-category"]').get(index),
      body,
    );
  };

  const open = () => viewsDropdownDriver().inputDriver.click();

  /**
   * Detect redesign mode by checking whether the popover trigger lives
   * inside `base` (legacy — standalone next to the dropdown) or only
   * inside the dropdown portal / body (redesign — suffix on selected item).
   */
  // const isRedesignMode = async () => {
  //   return !(
  //     await base.$('[data-hook="manage-view-popover-button"]').exists()
  //   );
  // };

  const openManageViewPopover = async () => {
    // In redesign mode the 3-dots button is inside the dropdown list on the
    // selected view, so we need to ensure the dropdown is open first.
    // In legacy mode opening the dropdown is harmless — the trigger is always
    // accessible in the component tree.
    const isOpen = await viewsDropdownDriver().dropdownLayoutDriver.isShown();
    if (!isOpen) {
      await open();
    }
    await manageViewPopover().open();
  };

  const saveNewViewClick = async () => {
    const isOpen = await viewsDropdownDriver().dropdownLayoutDriver.isShown();
    if (!isOpen) {
      await open();
    }

    // Redesign: "Save to New View" is in the dropdown footer
    const footerExists = await saveToNewViewFooter().exists();
    if (footerExists) {
      return saveToNewViewFooter().clickSaveNewView();
    }

    // Legacy: "Save to New View" is inside the ManageViewPopover
    await manageViewPopover().open();
    await manageViewPopover().clickSaveNewView();
  };

  const deleteViewActionClick = () => manageViewPopover().clickDeleteView();
  const saveViewChangesActionClick = () =>
    manageViewPopover().clickSaveChanges();
  const renameViewActionClick = () => manageViewPopover().clickRenameView();
  const setAsDefaultViewActionClick = () =>
    manageViewPopover().clickSetAsDefaultView();

  return {
    ...baseUniDriverFactory(base),
    _input: () => viewsDropdownDriverBase().$('input'),
    exists: () => viewsDropdownDriver().exists(),
    initialLoaderExists: async () =>
      (await getDropdownLayoutBase())
        .$('[data-hook="initial-loader"]')
        .exists(),
    /** Get the currently selected view name */
    getSelected: async () => {
      // When the dropdown is open and in editing mode (disableEditing=false),
      // the input value shows the search text and the selected label moves to
      // the placeholder. After onSelect fires (disableEditing=true) the value
      // switches back to the selected label but the dropdown may still be
      // visually shown. Try the value first; fall back to the placeholder.
      const isOpen = await viewsDropdownDriver().dropdownLayoutDriver.isShown();
      if (isOpen) {
        const selectedId =
          await viewsDropdownDriver().dropdownLayoutDriver.getSelectedOptionId();
        if (!selectedId) {
          return '';
        }
        const value = await viewsDropdownDriver().inputDriver.getValue();
        return value || viewsDropdownDriver().inputDriver.getPlaceholder();
      }
      return viewsDropdownDriver().inputDriver.getValue();
    },
    /** Get the dropdown input text */
    getInputValue: () => viewsDropdownDriver().inputDriver.getValue(),
    /** Indicates input is ready-only */
    getInputReadOnly: () => viewsDropdownDriver().inputDriver.getReadOnly(),
    /** Indicates input is focused */
    isInputFocused: () => viewsDropdownDriver().inputDriver.isFocus(),
    /** Get the currently selected view id */
    getSelectedId: () =>
      viewsDropdownDriver().dropdownLayoutDriver.getSelectedOptionId(),
    /** Checks if total is shown */
    hasTotal: () =>
      viewsDropdownDriver().inputDriver.suffixComponentExists('.total-count'),
    /** Opens views dropdown */
    open,
    /** Enter dropdown input text */
    enterText: (value: string) =>
      viewsDropdownDriver().inputDriver.enterText(value),
    /** Click dropdown input clear button */
    clickInputClearButton: () => viewsDropdownDriver().inputDriver.clickClear(),
    /** Indicates input clear button exists  */
    inputClearButtonExists: () =>
      viewsDropdownDriver().inputDriver.hasClearButton(),
    /** Get number of views */
    getViewsCount: async () =>
      viewsDropdownDriverBase().$$('[data-hook="view-item"]').count(),
    /** Get array of all view names in the dropdown */
    getViewsContent: async () =>
      viewsDropdownDriverBase().$$('[data-hook="view-item"]').text(),
    /** Get array popover content , like empty state */
    getViewsPopoverContent: async () =>
      viewsDropdownDriver().dropdownLayoutDriver.optionsContent(),
    /** Indicates whether the dropdown is open */
    isOpen: () => viewsDropdownDriver().dropdownLayoutDriver.isShown(),
    /** Get the placeholder test of the dropdown */
    getPlaceholderText: () =>
      viewsDropdownDriver().inputDriver.getPlaceholder(),
    /** Get modal driver for "Save View" */
    getSaveViewModal,
    /** Get modal driver for "Rename View" */
    getRenameViewModal,
    /** Get view list item driver by view id */
    getViewListItemById,
    /** Get view list item driver by view index */
    getViewListItemAt,
    /** Get category list item driver by category id */
    getCategoryListItemById,
    /** Get category list item driver by category index */
    getCategoryListItemAt,
    /** Get "all items" view list item */
    getAllItemsView: () => getCategoryListItemById('all-items-view'),
    /** Get number of categories */
    getCategoriesCount: async () =>
      viewsDropdownDriverBase().$$('[data-hook="view-category"]').count(),
    /** Get array of all category names in the dropdown */
    getCategoriesContent: async () =>
      viewsDropdownDriverBase().$$('[data-hook="view-category"]').text(),
    /** Check if view pending changes */
    isViewPendingChanges: async () =>
      viewsDropdownDriver().inputDriver.prefixComponentExists(
        '[data-hook="view-pending-changes"]',
      ),
    isDefaultView: async () =>
      viewsDropdownDriver().inputDriver.prefixComponentExists(
        '[data-hook="view-default"]',
      ),

    /** Indicates whether the Manage View popover exists */
    manageViewPopoverExists: () => manageViewPopover().exists(),
    /** Indicates whether the Manage View popover opened */
    isManageViewPopoverOpen: () => manageViewPopover().isOpen(),
    /** Opens the Manage View popover */
    openManageViewPopover,
    /** Clicks the Save Changes action in the Manage View popover */
    saveViewChangesActionClick,
    /** Clicks the Save to New View button (auto-detects redesign vs legacy) */
    saveNewViewActionClick: saveNewViewClick,
    /** Clicks the Rename action in the Manage View popover */
    renameViewActionClick,
    /** Clicks the Set as Default View action in the Manage View popover */
    setAsDefaultViewActionClick,
    /** Clicks the Delete action in the Manage View popover */
    deleteViewActionClick,
    /** Get DropdownLayoutOptionUniDriver of a Save Changes option */
    getSaveViewChangesBtn: () => manageViewPopover().getSaveChangesBtn(),
    /** Get the Save to New View button (auto-detects redesign vs legacy) */
    getSaveNewViewBtn: async () => {
      const isOpen = await viewsDropdownDriver().dropdownLayoutDriver.isShown();
      if (!isOpen) {
        await open();
      }
      // Redesign: footer button; Legacy: popover menu item
      const footerExists = await saveToNewViewFooter().exists();
      if (footerExists) {
        return saveToNewViewFooter().getSaveNewViewBtn();
      }

      // Fallback to popover (e.g. popover not yet open in legacy mode)
      return manageViewPopover().getSaveNewViewBtn();
    },
    /** Get DropdownLayoutOptionUniDriver of a Delete View option */
    getDeleteViewBtn: () => manageViewPopover().getDeleteViewBtn(),
    /** Get DropdownLayoutOptionUniDriver of a Rename option */
    getRenameViewBtn: () => manageViewPopover().getRenameViewBtn(),
    /** Get DropdownLayoutOptionUniDriver of a Set as Default View option */
    getSetAsDefaultViewBtn: () => manageViewPopover().getSetAsDefaultViewBtn(),

    /** Saves new view with a defined name and current filters / sort / columns */
    saveNewView: async (name: string) => {
      await saveNewViewClick();
      const saveViewModal = getSaveViewModal();
      await saveViewModal.fillViewNameInput(name);
      await saveViewModal.clickSaveButton();
    },
    /** Deletes the view with a given index */
    deleteView: async (ind: number) => {
      await open();
      await getViewListItemAt(ind).select();
      await openManageViewPopover();
      await deleteViewActionClick();
    },
    /** Saves changes to the current view */
    saveViewChanges: async () => {
      await openManageViewPopover();
      await saveViewChangesActionClick();
    },
    /** Renames the current view with a given name */
    renameView: async (name: string) => {
      await openManageViewPopover();
      await renameViewActionClick();

      const renameViewModal = getRenameViewModal();
      await renameViewModal.fillViewNameInput(name);
      await renameViewModal.clickSaveButton();
    },
    /** Sets a default view with a given index */
    setAsDefaultView: async (ind: number) => {
      await open();
      await getViewListItemAt(ind).select();
      await openManageViewPopover();
      await setAsDefaultViewActionClick();
    },
  };
};
