import { useRef, 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';
import noop from 'lodash/noop';

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: {}
} as Meta;

const createClasses = makeStyles<Theme>(theme => ({
  menuList: {
    marginRight: 0,
    maxHeight: 420
  }
}));

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

  const { multiple } = args;

  const [listItems, setListItems] = useState(args.listItems);
  const portionCount = useRef(1);
  const portion = [
    { id: 1, name: `test1-port${portionCount.current}` },
    { id: 2, name: `test2-port${portionCount.current}` },
    { id: 3, name: `test3-port${portionCount.current}` },
    { id: 4, name: `test4-port${portionCount.current}` },
    { id: 5, name: `test5-port${portionCount.current}` },
    { id: 6, name: `test6-port${portionCount.current}` },
    { id: 7, name: `test7-port${portionCount.current}` },
    { id: 8, name: `test8-port${portionCount.current}` },
    { id: 9, name: `test9-port${portionCount.current}` },
    { id: 10, name: `test10-port${portionCount.current}` }
  ];

  const groupPortion = [
    {
      name: `test1-port${portionCount.current}`,
      group: `${portionCount.current + 2} Group Title`,
      value: portionCount.current * 100 + 1
    },
    {
      name: `test2-port${portionCount.current}`,
      group: `${portionCount.current + 2} Group Title`,
      value: portionCount.current * 100 + 2
    },
    {
      name: `test3-port${portionCount.current}`,
      group: `${portionCount.current + 2} Group Title`,
      value: portionCount.current * 100 + 3
    },
    {
      name: `test4-port${portionCount.current}`,
      group: `${portionCount.current + 2} Group Title`,
      value: portionCount.current * 100 + 4
    },
    {
      name: `test5-port${portionCount.current}`,
      group: `${portionCount.current + 3} Group Title`,
      value: portionCount.current * 100 + 5
    },
    {
      name: `test6-port${portionCount.current}`,
      group: `${portionCount.current + 3} Group Title`,
      value: portionCount.current * 100 + 6
    },
    {
      name: `test7-port${portionCount.current}`,
      group: `${portionCount.current + 3} Group Title`,
      value: portionCount.current * 100 + 7
    }
  ];

  const groupExists = listItems.some(item => !!item.options);

  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);
    }
  };

  const fetchFunction = () => {
    portionCount.current = portionCount.current + 1;
    if (groupExists) {
      setListItems(prevState => {
        const newState = [...prevState];
        for (let i = 0; i < groupPortion.length; i++) {
          let index = newState.findIndex(item => item.name === groupPortion[i].group);
          if (index === -1) {
            index = newState.length;
            newState.push({
              id: groupPortion[i].group,
              name: groupPortion[i].group,
              options: []
            });
          }
          newState[index]?.options?.push({
            name: groupPortion[i].name,
            value: groupPortion[i].value
          });
        }
        return newState;
      });
    } else {
      setListItems(prevState => [...prevState, ...portion]);
    }
  };

  return (
    <MenuContent
      {...args}
      handleClick={handleMenuClick}
      listItems={listItems}
      handleDelete={handleDelete}
      onSortEnd={onSortEnd}
      classes={{
        menuList: styles.menuList
      }}
      infinityScrollProps={{
        ...args.infinityScrollProps,
        allItemsCount: args.infinityScrollProps?.allItemsCount || 0,
        fetchFunction: fetchFunction
      }}
    />
  );
};

export const InfinityScrollPrimary = InfinityTemplate.bind({});
InfinityScrollPrimary.args = {
  ariaLabel: 'List with Infinity Scroll',
  listItems: [
    { name: 'Item Number 1' },
    { name: 'Item Number 2' },
    { name: 'Item Number 3' },
    { name: 'Item Number 4' },
    { name: 'Item Number 5' },
    { 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: 'Action Icons 4', actionIcons: actionIcons.slice(0, 2) },
    { name: 'Action Icons 5', actionIcons: actionIcons.slice(2, 4) },
    { name: 'Action Icons 6', actionIcons: actionIcons.slice(0, 3) },
    { name: 'Disabled Item', disabled: true, selected: true },
    { name: 'Disabled Item 2', disabled: true, selected: true },
    { name: 'Disabled Item 3', disabled: true, selected: true }
  ],
  multiple: false,
  showSelectedIcon: true,
  sortable: false,
  variableSizeList: false,
  variableSizeListProps: {
    height: 420
  },
  infinityScrollProps: {
    fetchFunction: noop,
    allItemsCount: 100,
    threshold: 2
  },
  loadingText: 'Loading...'
};

const mockCompaniesMenuItems = getMockCompaniesMenuItems(10);
export const InfinityScrollWithGroups = InfinityTemplate.bind({});
InfinityScrollWithGroups.args = {
  ariaLabel: 'Grouped List with Infinity Scroll',
  listItems: [
    {
      id: '__first',
      name: '1 Group Title',
      options: mockCompaniesMenuItems.slice(0, 4)
    },
    {
      id: '__second',
      name: '2 Group Title',
      options: mockCompaniesMenuItems.slice(4, 8)
    },
    {
      id: '__third',
      name: '3 Group Title',
      options: mockCompaniesMenuItems.slice(8, 10)
    }
  ],
  multiple: true,
  infinityScrollProps: {
    fetchFunction: noop,
    allItemsCount: 100,
    threshold: 2
  },
  loadingText: 'Loading...'
};
