import React, { useEffect, useState } from 'react'

import { FilterMenu, type FilterStatesType } from './FilterMenu'
import Button from '../Button/Button'
import ButtonGroup from '../Button/ButtonGroup/ButtonGroup'
import { type ButtonGroupProps } from '../Button/ButtonGroup/ButtonGroup'
import Ellipsis from '../Ellipsis/Ellipsis'
import FormFooter from '../Form/FormFooter'
import Icon from '../Icons/Icon'
import { type IconStringList } from '../Icons/Icon.models'
import Pill from '../Pill/Pill'
import { SideDrawer } from '../SideDrawer/SideDrawer'
import { useMediaQuery } from '../../hooks/responsiveHooks'
import styles from './_filter.module.scss'
import { c } from '../../translations/LibraryTranslationService'

export type FilterProps<OptionType> = {
  /** Objects with key value pairs about what filter options can render in Filter body */
  filterStates: FilterStatesType<OptionType>
  /** Function to save selected filter options */
  filterCallout: (...params: unknown[]) => void
  /** Function to reset filter options to default */
  resetCallout: () => void
  /** Function to reset date selected from filter options */
  resetDate?: (...params: unknown[]) => void
  /** Display applied filter count if filter options are selected */
  appliedFilters?: unknown
  /** Function to call on change of any filter options */
  onChangeCallout?: (...params: unknown[]) => void
  /** Function to cancel  */
  cancelCallout: (...params: unknown[]) => void
  /** Function to open  */
  openCallout?: (...params: unknown[]) => void
  /** Anything which you would like to add in addition to Filter options  */
  children?: (props: {
    isOpen?: boolean
    close?: () => void
  }) => React.ReactNode
  /** Set boolean for loading state of filter */
  loading?: boolean
  /** Set boolean to enable/disable tab indexing */
  noTabIndex?: boolean
  /** The text that will display at the top of the popover */
  headerText?: string
  /** Enable/disable Filter button based on API status either loading or success */
  apiStatus?: string
  /** Disables the apply button on the filter form */
  disabled?: boolean
  /** Render filter children above other filter elements rather than the default of below */
  topChildren?: boolean
  /** Disables the filters button */
  disableFilterButton?: boolean
  /** Optionally hide the filter button text in mobile */
  hideMobileButtonText?: boolean
  /** Optionally display the Filter Button as a ButtonGroup */
  buttonGroupConfig?: Omit<ButtonGroupProps, 'styleType'>
  /** Optional prop to add a test id to the Filter for QA testing */
  qaTestId?: string
}
const Filter = <OptionType,>({
  filterStates = {},
  filterCallout,
  resetCallout,
  resetDate,
  appliedFilters,
  onChangeCallout,
  cancelCallout,
  openCallout,
  children,
  loading,
  noTabIndex,
  headerText,
  apiStatus,
  disabled,
  topChildren,
  disableFilterButton,
  hideMobileButtonText = false,
  buttonGroupConfig,
  qaTestId = 'filter',
}: FilterProps<OptionType>): React.JSX.Element => {
  const [openFilters, setOpenFilters] = useState(false)
  const isMobileView = useMediaQuery({ type: 'max', breakpoint: 'md' })
  const buttonGroupProps = buttonGroupConfig
    ? {
        ...buttonGroupConfig,
        buttons: [
          ...buttonGroupConfig.buttons,
          {
            icon: 'filter' as IconStringList,
            onClick: () => setOpenFilters(true),
            disabled: loading || disableFilterButton,
          },
        ],
      }
    : null

  useEffect(() => {
    openFilters && openCallout?.()
  }, [openFilters, openCallout])

  return (
    <div>
      {buttonGroupProps ? (
        <div className={styles.buttonGroupWrapper}>
          <ButtonGroup
            {...buttonGroupProps}
            qaTestId={`${qaTestId}-button-group`}
          />
          {appliedFilters ? (
            <span className={styles.appliedFiltersIndicator} />
          ) : null}
        </div>
      ) : (
        <Button
          as='button'
          qaTestId={`${qaTestId}-button`}
          tabIndex={noTabIndex ? -1 : undefined}
          className={styles.buttonStyle}
          onClick={() => setOpenFilters(true)}
          disabled={loading || disableFilterButton}
          {...(disableFilterButton && !loading
            ? { tooltip: { tooltipContent: c('noFiltersAvailable') } }
            : {})}
        >
          {loading ? (
            <>
              {c('loading')}
              <Ellipsis />
            </>
          ) : (
            <>
              <Icon
                icon='filter'
                iconSize='16px'
                color={disableFilterButton ? 'gray' : 'purple'}
              />
              {isMobileView && hideMobileButtonText ? null : (
                <span>
                  {Object.keys(filterStates as Record<string, unknown>)
                    ?.length > 0
                    ? c('filters')
                    : c('filter')}
                </span>
              )}
              {appliedFilters ? (
                <Pill color='blue' number={Number(appliedFilters)} />
              ) : null}
            </>
          )}
        </Button>
      )}
      <SideDrawer
        isOpen={openFilters}
        qaTestId={`${qaTestId}-side-drawer`}
        closeCallout={(isOutsideClick) => {
          setOpenFilters(false)
          if (isOutsideClick) {
            cancelCallout()
          }
        }}
        headerContent={headerText ?? c('filters')}
        footerContent={({ close }) => (
          <FormFooter
            resetButtonProps={{
              onClick: () => resetCallout(),
              children: c('resetFilters'),
            }}
            cancelButtonProps={{
              onClick: () => {
                cancelCallout()
                close()
              },
            }}
            saveButtonProps={{
              onClick: () => {
                filterCallout(filterStates)
                close()
              },
              disabled: apiStatus === 'loading' || disabled,
              children: c('apply'),
            }}
          />
        )}
      >
        {({ close }) => (
          <FilterMenu
            states={filterStates}
            close={close}
            onChangeCallout={onChangeCallout}
            loading={loading}
            topChildren={topChildren}
            isOpen={openFilters}
          >
            {children}
          </FilterMenu>
        )}
      </SideDrawer>
    </div>
  )
}

export default Filter
