import React, { useEffect, useMemo, useState } from 'react'
import { type Meta, type StoryObj } from '@storybook/react-vite'

import { DocsTemplate } from '../../../.storybook'
import MultiSelect from './MultiSelect'
import {
  generateArray,
  generateDummyNestedMultiSelectData,
  genericPropsMultiSelect,
  multiSelectDisabledList,
  multiSelectOptions,
  useApiMultiSelectStory,
} from './MultiSelectStoryHelpers'
import {
  CheckboxState,
  type DateCheckState,
  getFlattenNestedTreeList,
} from '../Form/NestedCheckboxHelper'

export default {
  title: 'Components/FormComponents/MultiSelect/Exposed',
  component: MultiSelect,
  parameters: {
    layout: 'centered',
    docs: {
      page: () => (
        <DocsTemplate
          description={
            <span>
              This version of the <code>MultiSelect</code> component is used to
              quickly see the multi-select form instead of opening the dropdown.
            </span>
          }
          infoBullets={[
            <span key='first-bullet'>
              Implement this version of <code>MultiSelect</code> component in
              forms, filtering interfaces, or settings sections where the height
              of its container is known.
            </span>,
            <span key='second-bullet'>
              This version of <code>MultiSelect</code> also has all the
              abilities of the base <code>MultiSelect</code> component like
              Search, disabling options initially and allowing secondary text
              for options etc.
            </span>,
          ]}
        />
      ),
    },
  },
} as Meta<typeof MultiSelect>

const nestedMultiSelectData = generateDummyNestedMultiSelectData()

const HandleMultiSelect = (args) => {
  const {
    options,
    selectedOptions,
    searchPlaceholder,
    noListDataText,
    maxHeight,
    loading,
    isPaginatable,
  } = args
  const [selected, setSelected] = useState(selectedOptions)

  const [searchText, setSearchText] = useState('')
  const { apiData, selectedData, fetchNew, setSelectedData } =
    useApiMultiSelectStory(searchText)

  return (
    <div style={{ width: '300px' }}>
      {isPaginatable ? (
        <MultiSelect
          searchBarProps={{
            ...args.searchBarProps,
            show: true,
            onChange: setSearchText,
          }}
          options={apiData}
          selectedOptions={selectedData}
          labelKey='title'
          callout={(selectedList) => {
            setSelectedData(selectedList)
          }}
          selectPlaceholder='--- Users ---'
          fetchData={fetchNew}
          hasMore={searchText.length === 0 && apiData.length < 100}
          exposed={args.exposed}
        />
      ) : (
        <MultiSelect
          {...args}
          labelKey='name'
          selectedOptions={selected}
          options={options}
          callout={(selectedList) => {
            setSelected(selectedList)
          }}
          searchPlaceholder={searchPlaceholder}
          noListDataText={noListDataText}
          maxHeight={maxHeight}
          loading={loading}
        />
      )}
    </div>
  )
}

const HandleNestedMultiSelect = (args) => {
  const { options, selectedOptions, noListDataText } = args
  const [selected, setSelected] = useState(selectedOptions)

  const flattenData = getFlattenNestedTreeList({
    nestedData: nestedMultiSelectData ?? [],
    childrenKey: 'children',
    parentKey: 'parent_category_id',
    idKey: 'id',
  })

  const defaultItemStates = useMemo(
    () =>
      flattenData.map((i) => ({
        id: i['id'] as string | number,
        state: CheckboxState.UNCHECKED,
      })),
    [flattenData],
  )
  const identifierKeys = {
    displayKey: 'name',
    idKey: 'id',
    parentKey: 'parent_category_id',
  }

  const tableConfig = [
    {
      label: '',
      dataKey: 'name',
      children: (data) => <span className='text-xs'>{data.name}</span>,
    },
  ]

  const [itemStates, setItemStates] =
    useState<DateCheckState[]>(defaultItemStates)

  return (
    <div style={{ width: 300 }}>
      <MultiSelect
        {...args}
        selectedOptions={selected}
        options={options}
        callout={(selectedList) => {
          setSelected(selectedList)
        }}
        noListDataText={noListDataText}
        labelKey='name'
        nestedConfig={{
          data: flattenData,
          itemStates: itemStates,
          setItemStates: setItemStates,
          identifierKeys: identifierKeys,
          tableConfig,
        }}
        searchBarProps={{
          ...args.searchBarProps,
          show: true,
        }}
      />
    </div>
  )
}
type Story = StoryObj<typeof MultiSelect>

const NestedTemplate: Story = {
  render: (args) => {
    return <HandleNestedMultiSelect {...args} />
  },
}

const Template: Story = {
  render: (args) => {
    return <HandleMultiSelect {...args} />
  },
}
const options = multiSelectOptions
const disabledList = multiSelectDisabledList

const genericProps = {
  ...genericPropsMultiSelect,
  exposed: true,
}
export const Basic: Story = {
  ...Template,
  args: {
    ...genericProps,
  },
}

export const SelectedOptions: Story = {
  ...Template,
  args: {
    ...genericProps,
    selectedOptions: [options[32], options[6]],
  },
}

export const DisabledOptions: Story = {
  ...Template,
  args: {
    ...genericProps,
    selectedOptions: [disabledList[23], disabledList[32], disabledList[3]],
    options: disabledList,
  },
}

export const ManyOptions: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: generateArray(1000),
  },
}

export const Nested: Story = {
  ...NestedTemplate,
  args: {
    ...genericProps,
    formLabelProps: {
      ...genericProps.formLabelProps,
      label: 'Category',
    },
    options: nestedMultiSelectData,
  },
}

export const LongNameOptions: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: [
      {
        ...options[0],
        name: 'This is a long option name that will wrap to the next line and continue with another sentence to demonstrate the wrapping behavior',
      },
      ...options.slice(1),
    ],
  },
}

export const WordBreak: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: [
      {
        ...options[0],
        name: 'This is a loooooooooooooooooooooooooooooooooooooooooong character name',
      },
      ...options.slice(1),
    ],
  },
}

export const WithSecondaryOptions: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: generateArray(50, true),
  },
}

export const MaxHeight: Story = {
  ...Template,
  args: {
    ...genericProps,
    maxHeight: 500,
  },
}

export const Loading: Story = {
  ...Template,
  args: {
    ...genericProps,
    loading: true,
  },
}

export const HideSelectAll: Story = {
  ...Template,
  args: {
    ...genericProps,
    hideSelectAll: true,
  },
}

export const MultiSelectWithPagination: Story = {
  render: (args) => {
    return <HandleMultiSelect {...args} isPaginatable={true} />
  },
}

export const ReorderableMultiSelect: Story = {
  ...Template,
  args: {
    ...genericProps,
    isReorderable: true,
  },
}

export const DisabledItemsSection: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: disabledList,
    disabledItemsSection: {
      enabled: true,
    },
  },
}

export const DisabledSectionHeaderTitle: Story = {
  ...Template,
  args: {
    ...genericProps,
    options: disabledList.map((item) =>
      item.disabled ? { ...item, secondaryOption: 'Secondary Text' } : item,
    ),
    disabledItemsSection: {
      enabled: true,
      primaryTitle: 'Removed',
      secondaryTitle: 'Reason',
    },
  },
}

export const DisabledSectionWithNoDisabledItems: Story = {
  ...Template,
  args: {
    ...genericProps,
    disabledItemsSection: {
      enabled: true,
    },
  },
}

export const NoBorder: Story = {
  ...Template,
  args: {
    ...genericProps,
    removeBorder: true,
  },
}

const HandleMultiSelectDisabledSectionWithCustomDisabledKey = (args) => {
  const { options, searchPlaceholder, noListDataText, maxHeight, loading } =
    args
  const [selected, setSelected] = useState<typeof options>([])
  const [listOptions, setListOptions] = useState(options)
  const [isMaxItemsSelected, setIsMaxItemsSelected] = useState(false)

  useEffect(() => {
    const unselectedItems = [
      ...options
        .filter(
          (option) =>
            !selected.find(
              (selectedOption) => selectedOption.name === option.name,
            ),
        )
        .map((option) => ({ ...option, disabled: isMaxItemsSelected })),
    ]
    setListOptions(unselectedItems)
  }, [selected, isMaxItemsSelected, setListOptions, options])

  return (
    <div style={{ width: '300px' }}>
      <MultiSelect
        {...args}
        labelKey='name'
        selectedOptions={selected}
        options={listOptions}
        callout={(selectedList) => {
          setSelected(selectedList)
          if (selectedList.length >= 5) {
            setIsMaxItemsSelected(true)
          } else {
            setIsMaxItemsSelected(false)
          }
        }}
        searchPlaceholder={searchPlaceholder}
        noListDataText={noListDataText}
        maxHeight={maxHeight}
        loading={loading}
      />
    </div>
  )
}

const DisabledSectionWithCustomDisabledKeyTemplate: Story = {
  render: ({ ...args }) => {
    return <HandleMultiSelectDisabledSectionWithCustomDisabledKey {...args} />
  },
}

export const DisabledSectionWithCustomDisabledKey: Story = {
  ...DisabledSectionWithCustomDisabledKeyTemplate,
  args: {
    ...genericProps,
    formLabelProps: {
      ...genericProps.formLabelProps,
      rightLabel: 'Max 5 options can be selected',
    },
    options: disabledList.map((item) =>
      item.disabled
        ? {
            ...item,
            secondaryOption: 'Secondary Text',
            notAllowed: true,
          }
        : item,
    ),
    disabledItemsSection: {
      enabled: true,
      primaryTitle: 'Removed',
      secondaryTitle: 'Reason',
      disabledItemsKey: 'notAllowed',
    },
  },
}
