import { useCallback, useMemo, useState } from 'react';
import { Story } from '@storybook/react';

import {
  MenuItem,
  processDropdownMenuItemsRecursive,
  toggleClickedDropdownMenuItem
} from '../../../../dropdown-menu';
import type {
  DropdownMenuItem,
  DropDownMenuProps,
  MenuContentProps
} from '../../../../dropdown-menu';

import { Select } from '../../../../@forms/select';
import type { SelectProps } from '../../../../@forms/select';

const MENU_CHECKBOX_SELECT_ALL_NAME = 'Select All';

type CheckboxState = 'default' | 'indeterminate' | 'selected';

export const NestedSelectAllTemplate: Story<SelectProps> = args => {
  const listItems = args.menuContentProps.listItems;
  const [selectItems, setSelectItems] = useState(listItems);
  const [checkboxState, setCheckboxState] = useState<CheckboxState>('default');

  const multipleSelectValues = useMemo(() => {
    const values: string[] = [];
    processDropdownMenuItemsRecursive(selectItems, item => {
      if (item.selected) values.push(item?.name?.toString() || '');
    });
    return values;
  }, [selectItems]);

  const [multipleDisplayListItems, setMultipleDisplayListItems] = useState(selectItems);
  const [secondaryMultipleListItems, setSecondaryMultipleListItems] = useState(selectItems);

  const forceCheckboxState = useCallback(
    (newCheckboxState: CheckboxState) => {
      if (newCheckboxState !== 'indeterminate') {
        const newListItems = processDropdownMenuItemsRecursive(selectItems, item => ({
          ...item,
          selected: newCheckboxState === 'selected'
        }));
        setSelectItems(newListItems);
        setMultipleDisplayListItems(newListItems);
      }
      setCheckboxState(newCheckboxState);
    },
    [selectItems]
  );

  const getCheckboxState: (listItems: DropdownMenuItem[]) => CheckboxState = listItems => {
    let listItemsCount = 0;
    let selectedItemsCount = 0;
    processDropdownMenuItemsRecursive(listItems, item => {
      if (item.selected) selectedItemsCount++;
      listItemsCount++;
    });
    if (selectedItemsCount < 1) {
      return 'default';
    } else if (selectedItemsCount > listItemsCount - 1) {
      return 'selected';
    } else {
      return 'indeterminate';
    }
  };

  const handleMultipleValuesChange: NonNullable<DropDownMenuProps['handleClick']> =
    newValue => () => {
      let multipleListItems = multipleDisplayListItems;
      const newListItems = processDropdownMenuItemsRecursive(selectItems, item => {
        const isClickedItem: boolean = item.name === newValue;
        const newItem = toggleClickedDropdownMenuItem(isClickedItem)(item);
        return newItem;
      });

      const newCheckboxState = getCheckboxState(newListItems);
      setCheckboxState(newCheckboxState);
      setSelectItems(newListItems);

      multipleListItems = processDropdownMenuItemsRecursive(multipleListItems, item =>
        toggleClickedDropdownMenuItem(item.name === newValue)(item)
      );
      setMultipleDisplayListItems(multipleListItems);
      setSecondaryMultipleListItems(multipleListItems);
    };

  const handleSelectClear: MenuContentProps['clearSelectItems'] = useCallback(
    () => forceCheckboxState('default'),
    [forceCheckboxState]
  );

  const handleSelectAllClick: NonNullable<DropDownMenuProps['handleClick']> = useCallback(
    newValue => () => forceCheckboxState(checkboxState !== 'selected' ? 'selected' : 'default'),
    [checkboxState, forceCheckboxState]
  );

  const InsertBeforeList = useCallback(
    () => (
      <MenuItem
        name={MENU_CHECKBOX_SELECT_ALL_NAME}
        checkboxProps={{ indeterminate: checkboxState === 'indeterminate' }}
        multiple
        selected={checkboxState === 'selected'}
        handleClick={handleSelectAllClick}
      />
    ),
    [handleSelectAllClick, checkboxState]
  );

  return (
    <Select
      {...args}
      value={multipleSelectValues}
      menuContentProps={{
        ...args.menuContentProps,
        listItems: multipleDisplayListItems,
        InsertBeforeList: args.menuContentProps.InsertBeforeList || InsertBeforeList,
        defaultListItems: secondaryMultipleListItems,
        handleClick: handleMultipleValuesChange,
        clearSelectItems: handleSelectClear
      }}
    />
  );
};
