import React, { useMemo, useState } from 'react'
import { type Meta, type StoryObj } from '@storybook/react-vite'
import { type Placement } from '@floating-ui/react'
import { type DateRange } from 'react-day-picker'

import { DocsTemplate } from '../../../.storybook'
import ExposedFilterComponent from './ExposedFilter'
import { type MultiSelectDataItemBase } from '../MultiSelect/MultiSelect'
import { type MinMaxRange } from '../RangeFilter/RangeFilter'
import {
  type ExposedFilterNameType,
  type ExposedFilterProps,
} from './ExposedFilter.models'
import {
  CheckboxState,
  type DateCheckState,
  getFlattenNestedTreeList,
} from '../Form/NestedCheckboxHelper'
import { generateDummyNestedMultiSelectData } from '../MultiSelect/MultiSelectStoryHelpers'
import FormFooter from '../Form/FormFooter'
import Checkbox from '../Form/Checkbox'
interface FilterType extends MultiSelectDataItemBase, ExposedFilterNameType {}

const meta: Meta<typeof ExposedFilter> = {
  title: 'Components/ExposedFilter/ExposedFilter',
  component: ExposedFilterComponent,
  parameters: {
    design: {
      type: 'figma',
      url: 'https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=14732-85850&p=f&t=9R4mlUY42yEaNlLp-0',
    },
    docs: {
      page: () => (
        <DocsTemplate
          figmaLink='https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=14732-85850&p=f&t=9R4mlUY42yEaNlLp-0'
          description={
            <span>
              The <code>ExposedFilter</code> component can be used when filters
              need to be exposed directly on page.
            </span>
          }
          infoBullets={[
            <span key='first-bullet'>
              Utilize the <strong>ExposedFilter</strong> component to expose
              filters directly without SideDrawer
            </span>,
          ]}
        />
      ),
    },
  },
}

export default meta

type Story = StoryObj<typeof ExposedFilter>

const generatePaginatedData = (count: number) => {
  return Array.from({ length: count }, (_, index) => ({
    id: index + 1,
    name: `Status ${index + 1}`,
  }))
}

const paginatedStatuses = generatePaginatedData(100)

const ExposedFilter = (args) => {
  interface FilterStateType {
    status: FilterType[]
    date?: Date
    dateRange?: DateRange
    priority?: FilterType
    amount?: MinMaxRange
    nestedItemStates?: {
      id: string | number
      state: CheckboxState
    }[]
    modal?: string[]
  }
  const [filtersState, setFiltersState] = useState<FilterStateType>({
    status: [],
    date: undefined,
    dateRange: undefined,
    priority: undefined,
    amount: { min: undefined, max: undefined },
    nestedItemStates: [],
    modal: [],
  })

  const [tempModalSelection, setTempModalSelection] = useState<string[]>(
    filtersState?.modal || [],
  )
  const [isModalOpen, setIsModalOpen] = useState(false)

  const onChangeCallout: ExposedFilterProps<FilterType>['onChangeCallout'] = (
    filterName,
    value,
  ) => {
    setFiltersState((prevState) => ({
      ...prevState,
      [filterName]: value,
    }))
    if (filterName === 'modal') {
      setTempModalSelection((value as string[]) || [])
    }
  }

  const nestedMultiSelectData = generateDummyNestedMultiSelectData()

  const flattenData = useMemo(
    () =>
      getFlattenNestedTreeList({
        nestedData: nestedMultiSelectData ?? [],
        childrenKey: 'children',
        parentKey: 'parent_category_id',
        idKey: 'id',
      }),
    [nestedMultiSelectData],
  )
  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)

  if (args.type === 'multi-select') {
    if (args.stateName === 'nestedItemStates') {
      return (
        <ExposedFilterComponent
          {...args}
          multiSelectProps={{
            selectedOptions: filtersState.nestedItemStates,
            options: nestedMultiSelectData,
            labelKey: 'name',
            nestedConfig: {
              data: flattenData,
              itemStates,
              setItemStates,
              identifierKeys,
              tableConfig,
            },
          }}
          onChangeCallout={onChangeCallout}
        />
      )
    } else
      return (
        <ExposedFilterComponent
          {...args}
          labelName={args.labelName}
          multiSelectProps={{
            ...args.multiSelectProps,
            selectedOptions: filtersState.status,
          }}
          onChangeCallout={onChangeCallout}
        />
      )
  } else if (args?.dateProps?.type === 'single') {
    return (
      <ExposedFilterComponent
        {...args}
        dateProps={{
          ...args.dateProps,
          selectedDate: filtersState.date,
        }}
        onChangeCallout={onChangeCallout}
      />
    )
  } else if (args?.dateProps?.type === 'range') {
    return (
      <ExposedFilterComponent
        {...args}
        dateProps={{
          ...args.dateProps,
          selectedDateRange: filtersState.dateRange,
        }}
        onChangeCallout={onChangeCallout}
      />
    )
  } else if (args.type === 'select' && args.disabled) {
    return (
      <ExposedFilterComponent
        {...args}
        labelName={args.labelName}
        searchBarProps={{
          ...args.searchBarProps,
        }}
      />
    )
  } else if (args.type === 'select') {
    return (
      <ExposedFilterComponent
        {...args}
        labelName={args.labelName}
        selectProps={{
          ...args.selectProps,
          selectedOption: filtersState.priority,
        }}
        onChangeCallout={onChangeCallout}
      />
    )
  } else if (args.type === 'range') {
    return (
      <ExposedFilterComponent
        {...args}
        labelName={args.labelName}
        rangeProps={{
          selectedValues: filtersState.amount,
        }}
        onChangeCallout={onChangeCallout}
      />
    )
  } else if (args.type === 'modal') {
    return (
      <ExposedFilterComponent
        {...args}
        labelName={args.labelName}
        openCallout={() => setIsModalOpen(true)}
        selectedOption={filtersState.modal}
        modalProps={{
          isOpen: isModalOpen,
          closeCallout: () => {
            setIsModalOpen(false)
          },
          size: 'sm',
          headerContent: 'Item Filter',
          footerContent: (
            <FormFooter
              saveButtonProps={{
                onClick: () => {
                  setFiltersState((prevState) => ({
                    ...prevState,
                    modal: tempModalSelection, // update main state on Save
                  }))
                  setIsModalOpen(false)
                },
                children: 'filter',
                styleType: 'primary',
              }}
              cancelButtonProps={{
                onClick: () => {
                  setIsModalOpen(false)
                },
              }}
            />
          ),
          children: (
            <div className='flex flex-col gap-4'>
              <div className='flex flex-col gap-2'>
                <Checkbox
                  label='P0NEIWB5'
                  checked={tempModalSelection.includes('P0NEIWB5')}
                  callout={() => {
                    setTempModalSelection((prev) =>
                      prev.includes('P0NEIWB5')
                        ? prev.filter((item) => item !== 'P0NEIWB5')
                        : [...prev, 'P0NEIWB5'],
                    )
                  }}
                  checkboxColor='blue'
                  type='checkbox'
                />

                <Checkbox
                  label='P0OGSJWM'
                  checked={tempModalSelection.includes('P0OGSJWM')}
                  callout={() => {
                    setTempModalSelection((prev) =>
                      prev.includes('P0OGSJWM')
                        ? prev.filter((item) => item !== 'P0OGSJWM')
                        : [...prev, 'P0OGSJWM'],
                    )
                  }}
                  checkboxColor='blue'
                  type='checkbox'
                />
              </div>
            </div>
          ),
        }}
        onChangeCallout={onChangeCallout}
      />
    )
  }
}
const Template: Story = {
  render: (args) => <ExposedFilter {...args} />,
}

const statuses = [
  { id: 1, name: 'Created' },
  { id: 2, name: 'Arrived' },
  { id: 3, name: 'Processed' },
  { id: 4, name: 'Receiving' },
  { id: 5, name: 'Canceled' },
  { id: 6, name: 'Pending' },
  { id: 7, name: 'In Transit' },
  { id: 8, name: 'Delivered' },
  { id: 9, name: 'Returned' },
  { id: 10, name: 'On Hold' },
  { id: 11, name: 'Backordered' },
  { id: 12, name: 'Failed' },
  { id: 13, name: 'Completed' },
  { id: 14, name: 'Refunded' },
  { id: 15, name: 'Shipped' },
  { id: 16, name: 'Pre-ordered' },
  { id: 17, name: 'Out of Stock' },
  { id: 18, name: 'Partially Shipped' },
  { id: 19, name: 'Awaiting Approval' },
  { id: 20, name: 'Quality Check' },
  { id: 21, name: 'Rejected' },
  { id: 22, name: 'Disputed' },
  { id: 23, name: 'Under Review' },
  { id: 24, name: 'Damaged' },
  { id: 25, name: 'Archived' },
]

const multiSelectProps = {
  options: statuses,
  searchBarProps: {
    placeholder: 'Search',
  },
  emptyStateProps: {
    primaryText: 'No Status Found',
    secondaryText: 'Try searching for a different status',
  },
  labelKey: 'name',
}

const priorities = [
  { id: 1, name: 'High' },
  { id: 2, name: 'Medium' },
  { id: 3, name: 'Low' },
]

const selectProps = {
  options: priorities,
  searchBarProps: {
    placeholder: 'Search priorities',
  },
  emptyStateProps: {
    primaryText: 'No Priority Found',
    secondaryText: 'Try searching for a different priority',
  },
  labelKey: 'name',
}

export const MultiSelect: Story = {
  ...Template,
  args: {
    multiSelectProps: multiSelectProps,
    type: 'multi-select',
    labelName: 'Status',
    stateName: 'status',
  },
}
export const MultiSelectWithPagination: Story = {
  ...Template,
  args: {
    multiSelectProps: {
      ...multiSelectProps,
      options: paginatedStatuses,
      fetchData: () => {
        // Simulate API call for pagination
        console.log('Fetching more data...')
      },
      hasMore: true,
      isFetching: false,
    },
    type: 'multi-select',
    labelName: 'Status',
    stateName: 'status',
  },
}
export const MultiSelectWithEmptyState: Story = {
  ...Template,
  args: {
    multiSelectProps: {
      options: [],
      searchBarProps: {
        placeholder: 'Search',
      },
      emptyStateProps: {
        primaryText: 'No records found',
        secondaryText: 'Try to change your search',
      },
    },
    type: 'multi-select',
    labelName: 'Status',
    stateName: 'status',
  },
}
export const Date: Story = {
  ...Template,
  args: {
    type: 'date',
    dateProps: { type: 'single' },
    labelName: 'Date',
    stateName: 'date',
  },
}

export const DateRangeFilter: Story = {
  ...Template,
  args: {
    type: 'date',
    dateProps: { type: 'range' },
    labelName: 'Date Range',
    stateName: 'dateRange',
  },
}

export const Select: Story = {
  ...Template,
  args: {
    selectProps: selectProps,
    type: 'select',
    labelName: 'Priority',
    stateName: 'priority',
  },
}

export const Range: Story = {
  ...Template,
  args: {
    type: 'range',
    labelName: 'Amount',
    stateName: 'amount',
  },
}

export const Nested: Story = {
  ...Template,
  args: {
    type: 'multi-select',
    labelName: 'Nested',
    stateName: 'nestedItemStates',
  },
}

export const Modal: Story = {
  ...Template,
  args: {
    type: 'modal',
    labelName: 'Modal',
    stateName: 'modal',
  },
}

export const DisabledFilterOption: Story = {
  ...Template,
  args: {
    selectProps: selectProps,
    type: 'select',
    disabled: true,
    disabledTooltip: {
      tooltipContent: 'This filter is disabled',
      position: 'top' as Placement,
    },
    labelName: 'Priority',
    stateName: 'priority',
  },
}
