import { useCallback, useMemo, useState } from 'react';
import { Args, ArgTypes, Meta, Story } from '@storybook/react';
import { AvatarProps } from '../../avatar';
import AvatarListItem from './components/avatar-list-item';

import { Autocomplete } from './autocomplete';
import type { AutocompleteProps, AutocompleteOptionProps } from './types';
import type { DropDownMenuProps } from '../../dropdown-menu';
import { stringToColor } from '../../../utils';

const mockItems: AutocompleteOptionProps[] = [];
for (let i = 1; i <= 20; i++) {
  const randomNum = Math.random() * 10;
  const randomStr = randomNum.toString(36).substring(2);
  const randomText = randomNum < 5 ? ' - ' + randomStr.substring(Math.floor(randomNum)) : '';
  mockItems.push({
    name: `Item${i}${randomText}`,
    selected: false
  });
}

const autocompleteItems = mockItems;

const argTypes: Partial<ArgTypes<Args>> = {
  size: {
    description: 'Set the size of the input.',
    options: ['small', 'medium'],
    control: {
      type: 'select'
    },
    defaultValue: {
      summary: 'medium'
    }
  },
  placeholder: {
    description: 'Placeholder to be displayed when no value is selected.',
    table: {
      defaultValue: {
        summary: ''
      }
    }
  },
  multiple: {
    description: 'Enable multiple selection functionality (i.e chips).',
    control: {
      type: 'boolean'
    }
  },
  defaultLimitTags: {
    description: 'Maximum number of tags to be seen on focus.',
    table: {
      defaultValue: {
        summary: 2
      }
    }
  },
  showLimitTagsTooltip: {
    description:
      'Whether to show tooltip with a list of tags or not (works only when `multiple` is enabled).',
    control: {
      type: 'boolean'
    }
  },
  freeSolo: {
    description: 'Enable text input (i.e chips creation, works only when `multiple` is enabled).',
    control: {
      type: 'boolean'
    }
  },
  options: {
    description: 'Array of options (each option is of type `AutocompleteOptionProps`).',
    control: {
      type: 'array'
    }
  },
  handleClear: {
    description:
      'Callback to be fired on field clear icon click. Will affect only when `multiple` is provided.'
  },
  handleCreate: {
    description:
      'Callback to be fired when the user enters a new value. Will affect only when `multiple` and `freeSolo` are provided.'
  },
  handleDelete: {
    description:
      'Callback to be fired on tag clear icon click. Will affect only when `multiple` is provided. @param {AutocompleteOptionProps[]} newValue The new value that should be set.'
  },
  handleTextChangeCB: {
    description:
      'Callback which is called on text change when `multiple` set to `true`. Should be used to filter `displayOptions`.'
  },
  handleMenuClick: {
    description: 'Callback to be fired on menu item click.'
  },
  renderInput: {
    description: 'Render the input. @param {object} params. @returns {ReactNode}'
  }
};

export default {
  component: Autocomplete,
  title: 'Forms/Autocomplete/Chips Grouping',
  argTypes
} as Meta;

const Template: Story<AutocompleteProps> = args => {
  const { defaultValue, options } = args;

  const selectedOptions = useMemo(() => {
    if (!defaultValue) return options;
    const defaultValues = (
      Array.isArray(defaultValue) ? defaultValue : [defaultValue]
    ) as AutocompleteOptionProps[];
    return options?.map(option => ({
      ...option,
      selected: !!defaultValues?.find(value => option?.name === value?.name)
    }));
  }, [defaultValue, options]);

  // Autocomplete single
  const [autocompleteOptionsSingle, setAutocompleteOptionsSingle] = useState(selectedOptions);

  const handleAutocompleteItemClickSingle: NonNullable<DropDownMenuProps['handleClick']> =
    v => () => {
      setAutocompleteOptionsSingle(
        autocompleteOptionsSingle.map(o => ({
          ...o,
          selected: v === o.name ? !o.selected : false
        }))
      );
    };

  const autocompleteValueSingle = useMemo(
    () => autocompleteOptionsSingle.find(o => o.selected) || ({} as AutocompleteOptionProps),
    [autocompleteOptionsSingle]
  );

  // Autocomplete multiple
  const [autocompleteOptionsMultiple, setAutocompleteOptionsMultiple] = useState(selectedOptions);

  const handleAutocompleteItemClickMultiple: NonNullable<DropDownMenuProps['handleClick']> =
    v => () => {
      setAutocompleteOptionsMultiple(
        autocompleteOptionsMultiple.map(o => ({
          ...o,
          selected: v === o.name ? !o.selected : o.selected
        }))
      );
    };

  const autocompleteValueMultiple = useMemo(
    () => autocompleteOptionsMultiple.filter(o => o.selected),
    [autocompleteOptionsMultiple]
  );

  const [textMultiple, setTextMultiple] = useState('');

  const displayOptionsMultiple = useMemo(() => {
    if (!textMultiple) {
      return autocompleteOptionsMultiple;
    }
    return autocompleteOptionsMultiple.filter(o => {
      const normalizedName = o.name.toString().toLowerCase();
      const words = [normalizedName];
      if (o.additionalProps?.subtext)
        words.push((o.additionalProps?.subtext as string).toString().toLowerCase());
      return words.some(word => word.includes(textMultiple));
    });
  }, [autocompleteOptionsMultiple, textMultiple]);

  const handleAutocompleteMultipleTextChange: AutocompleteProps['handleTextChangeCB'] = useCallback(
    e => {
      setTextMultiple(e.target.value);
    },
    []
  );

  // Autocomplete freeSolo
  const handleAutocompleteClear: AutocompleteProps['handleClear'] = useCallback(() => {
    setAutocompleteOptionsMultiple(
      autocompleteOptionsMultiple.map(option => ({
        ...option,
        selected: false
      }))
    );
  }, [autocompleteOptionsMultiple]);

  const handleAutocompleteCreate: AutocompleteProps['handleCreate'] = useCallback(
    (e, v) => {
      const value = v.slice(-1)[0]?.toString();
      value &&
        setAutocompleteOptionsMultiple(
          autocompleteOptionsMultiple.concat([
            {
              name: value,
              selected: true
            }
          ])
        );
    },
    [autocompleteOptionsMultiple]
  );

  const handleAutocompleteDelete: AutocompleteProps['handleDelete'] = useCallback((e, v) => {
    setAutocompleteOptionsMultiple(v);
  }, []);

  return (
    <Autocomplete
      handleClear={handleAutocompleteClear}
      handleCreate={handleAutocompleteCreate}
      handleDelete={handleAutocompleteDelete}
      {...args}
      value={args.multiple ? autocompleteValueMultiple : autocompleteValueSingle}
      options={args.multiple ? autocompleteOptionsMultiple : autocompleteOptionsSingle}
      handleMenuClick={
        args.multiple ? handleAutocompleteItemClickMultiple : handleAutocompleteItemClickSingle
      }
      displayOptions={displayOptionsMultiple}
      handleTextChangeCB={handleAutocompleteMultipleTextChange}
    />
  );
};

export const ChipsWithLimitTags = Template.bind({});
ChipsWithLimitTags.args = {
  size: 'medium',
  placeholder: '',
  multiple: true,
  defaultLimitTags: 2,
  showLimitTagsTooltip: false,
  freeSolo: false,
  options: autocompleteItems,
  defaultValue: autocompleteItems.slice(0, 12),
  handleDelete: () => alert('Will delete a single chip')
};

export const ActiveWithoutCollapsing = Template.bind({});
ActiveWithoutCollapsing.args = {
  size: 'medium',
  placeholder: '',
  multiple: true,
  defaultLimitTags: -1,
  alwaysExpand: true,
  showLimitTagsTooltip: true,
  freeSolo: true,
  options: autocompleteItems,
  defaultValue: autocompleteItems.slice(0, 12),
  handleDelete: () => alert('Will delete a single chip')
};

export const ActiveWithCollapsing = Template.bind({});
ActiveWithCollapsing.args = {
  size: 'medium',
  placeholder: 'Type text',
  multiple: true,
  defaultLimitTags: 2,
  showLimitTagsTooltip: true,
  freeSolo: true,
  alwaysExpand: false,
  options: []
};

export const AutocompleteWithAvatar = Template.bind({});

const avatarMapFN = (item: AutocompleteOptionProps) => {
  const { name, additionalProps } = item;
  const avatarProps: AvatarProps = {
    backgroundColor: stringToColor(name.toString()),
    customSize: additionalProps?.type === 'person' ? 24 : 32,
    variant: additionalProps?.type === 'person' ? 'circular' : 'rounded',
    src: additionalProps?.src as string
  };
  return {
    id: name,
    name: name,
    textNode: (
      <AvatarListItem
        name={name.toString()}
        subtext={additionalProps?.subtext as string}
        avatarProps={avatarProps}
      />
    )
  };
};

AutocompleteWithAvatar.args = {
  options: [
    {
      name: 'Dima Kurdon',
      additionalProps: { subtext: '123@kurdon.com', type: 'person' }
    },
    {
      name: 'Tal Dangur',
      additionalProps: { subtext: 'tal@dangur.com', type: 'person' }
    },
    {
      name: 'Blumshapiro',
      additionalProps: {
        subtext: 'Blumshapiro',
        type: 'company',
        src: 'https://i.pinimg.com/originals/e5/a9/e8/e5a9e877bcacdc5713d2a8f98412762d.png'
      }
    },
    {
      name: 'Something',
      additionalProps: {
        subtext: 'Something Something',
        type: 'company'
      }
    }
  ],
  showSearchIcon: true,
  listItemsMapFN: avatarMapFN
};
