import { useState } from 'react';
import type { Story, Meta } from '@storybook/react';
import { randCompanyName } from '@ngneat/falso';

import { makeStyles, Theme } from '../../@styles';
import { arrayMove } from '../../../utils';
import {
  areEqualDropdownMenuItems,
  filterDropdownMenuItemsRecursive,
  processDropdownMenuItemsRecursive
} from '../helpers';

import { MenuContent } from '../dropdown-menu';
import type { MenuContentProps, MenuItemProps } from '../types';
import { actionIcons } from '../__mocks__/menuItems';

function getMockCompaniesMenuItems(length = 10) {
  return randCompanyName({ length }).map(
    (companyName, index) =>
      ({
        name: companyName,
        value: index,
        selected: false
      } as MenuItemProps)
  );
}

export default {
  component: MenuContent,
  title: 'Forms/Dropdown Menu/Menu Content',
  argTypes: {
    listItems: {
      description: 'The items which will be shown in the list.'
    },
    multiple: {
      description:
        'Allow multiple selection. Notice your selection logic should also support multiple selection.'
    },
    showSelectedIcon: {
      description: 'Whether or not to show selected icon on single selection.'
    },
    search: {
      description:
        'Whether or not to allow searching items inside the menu, notice you must pass `handleSearchChangeCallback` to make it work.'
    },
    searchPlaceholder: {
      description: 'Place holder for the search field.'
    },
    deletable: {
      description:
        'Whether or not to show the delete icon for menu items, notice you must pass `handleDelete` to make it work.'
    },
    width: {
      description: 'The width of the menu.'
    },
    sortable: {
      description:
        'Whether or not to show the sort icon for menu items, notice you must pass `onSortEnd` to make it work.'
    },
    onSortEnd: {
      description: 'Callback which is fired on sort end.'
    },
    handleSearchChangeCallback: {
      description: 'Callback which is fired on search text change.'
    },
    bottomButtonText: {
      description:
        'If passed, a button will appear in the bottom of the menu, pass `bottomButtonClickHandler` to make it work.'
    },
    bottomButtonClickHandler: {
      description: 'Call back which will be fired on click the bottom button.'
    },
    handleDelete: {
      description: 'Call back which will be fired on click a delete icon.'
    },
    handleClick: {
      description: 'Call back which will be fired on clicking a menu item.'
    }
  }
} as Meta;

const createClasses = makeStyles<Theme>(theme => ({
  menuList: {
    maxHeight: 'none'
  }
}));

const Template: Story<MenuContentProps> = args => {
  const styles = createClasses();

  const { multiple } = args;

  const [listItems, setListItems] = useState(args.listItems);

  const handleMenuClick: NonNullable<MenuContentProps['handleClick']> = (name, value) => () => {
    const itemToSelect = { name, value };
    const newItems = processDropdownMenuItemsRecursive(listItems, item => {
      const areEqual = areEqualDropdownMenuItems(item, itemToSelect);
      if (multiple ? areEqual : areEqual || item.selected) {
        return {
          ...item,
          selected: !item.selected
        };
      }
      return item;
    });
    setListItems(newItems);
  };

  const handleDelete: MenuContentProps['handleDelete'] = (name, value) => event => {
    event.stopPropagation();
    const itemToDelete = { name, value };
    const newItems = filterDropdownMenuItemsRecursive(
      listItems,
      item => !areEqualDropdownMenuItems(item, itemToDelete)
    );
    setListItems(newItems);
  };

  // @todo: fix issue with groups sorting
  const onSortEnd: MenuContentProps['onSortEnd'] = sortArgs => {
    const { oldIndex, newIndex } = sortArgs;
    if (oldIndex !== newIndex) {
      const newArray = arrayMove(listItems, oldIndex, newIndex);
      setListItems(newArray);
    }
  };

  return (
    <MenuContent
      {...args}
      handleClick={handleMenuClick}
      listItems={listItems}
      handleDelete={handleDelete}
      onSortEnd={onSortEnd}
      classes={{
        menuList: styles.menuList
      }}
    />
  );
};

export const Primary = Template.bind({});
Primary.args = {
  ariaLabel: 'Items List',
  listItems: [
    { name: 'Item Number 1' },
    { name: 'Item Number 2' },
    { name: 'Item Number 3' },
    { name: 'Action Icons 1', actionIcons: actionIcons.slice(0, 2) },
    { name: 'Action Icons 2', actionIcons: actionIcons.slice(2, 4) },
    { name: 'Action Icons 3', actionIcons: actionIcons.slice(0, 3) },
    { name: 'Disabled Item', disabled: true, selected: true }
  ],
  multiple: false,
  showSelectedIcon: true,
  search: false,
  searchDebounceTime: 0,
  searchHighlight: true,
  searchPlaceholder: '',
  deletable: false,
  sortable: false,
  bottomButtonText: '',
  variableSizeList: false,
  variableSizeListProps: {
    height: 420
  }
};

export const WithSearch = Template.bind({});
WithSearch.args = {
  ariaLabel: 'Searchable List',
  listItems: getMockCompaniesMenuItems(100),
  multiple: true,
  showSelectedIcon: false,
  search: true,
  noOptionsText: 'No options',
  noResultsText: 'No results',
  deletable: false,
  sortable: false,
  searchHighlight: true,
  searchPlaceholder: 'Search placeholder',
  bottomButtonText: '',
  variableSizeList: false,
  variableSizeListProps: {
    height: 420
  }
};

const mockCompaniesMenuItems = getMockCompaniesMenuItems(50);

export const WithGroups = Template.bind({});
WithGroups.args = {
  ariaLabel: 'Grouped List',
  listItems: [
    {
      id: '__first',
      name: 'First Group Title',
      options: mockCompaniesMenuItems.slice(0, 10)
    },
    {
      id: '__second',
      name: 'Second Group Title',
      options: mockCompaniesMenuItems.slice(10, 35)
    },
    {
      id: '__third',
      name: 'Third Group Title',
      options: mockCompaniesMenuItems.slice(35, 45)
    },
    {
      id: '__forth',
      name: 'Forth Group Title',
      options: mockCompaniesMenuItems.slice(45)
    }
  ],
  multiple: true,
  search: false,
  searchDebounceTime: 0,
  searchHighlight: true,
  searchPlaceholder: 'Search placeholder',
  variableSizeList: false,
  variableSizeListProps: {
    height: 420
  }
};

export const DynamicActions = Template.bind({});
DynamicActions.args = {
  ariaLabel: 'Dynamic Action Icons',
  listItems: mockCompaniesMenuItems,
  modifyMenuItem: props =>
    props.selected
      ? {
          actionIcons: [],
          showSelectedIcon: true
        }
      : {
          actionIcons: actionIcons.slice(0, 1)
        },
  search: false,
  searchHighlight: true,
  searchPlaceholder: 'Search placeholder',
  deletable: false,
  sortable: false,
  bottomButtonText: '',
  variableSizeList: false,
  variableSizeListProps: {
    height: 420
  }
};
