import React, {
  createContext,
  useContext,
  PropsWithChildren,
  RefObject,
  MutableRefObject,
  useMemo,
} from 'react'
import { DateRange } from 'react-day-picker'

import { AgeCategoryCount, Location, FilterBarTypes } from '../FilterBarTypes'
import { useFilterActions, useFilterState, useFilterRefs } from '../hooks'

type FilterBarProviderProps = PropsWithChildren<FilterBarTypes>

type FilterBarContextType = FilterBarTypes & {
  selectedFilter: string | boolean
  ageCategoryCounts: AgeCategoryCount
  categories: number
  calendarRange?: DateRange
  selectedPath: string
  innerLoading: boolean
  selectedLocations: Location[]

  setSelectedLocations: (val: Location[]) => void
  setCalendarRange: (val: DateRange | undefined) => void
  setSelectedFilter: (val: string | boolean) => void
  setAgeCategoryCounts: (val: AgeCategoryCount) => void
  setCategories: (val: number) => void
  setSelectedPath: (val: string) => void

  handleSelectedFilter: (id: string | boolean) => void
  handleSubmit: () => void
  updateGuestsCount: (id: string, newCount: number) => void
  handleResetFilters: () => void

  // Refs
  previouslyFocusedButtonRef: MutableRefObject<HTMLButtonElement | null>
  panelRef: MutableRefObject<HTMLDivElement | null>
  buttonRefs: MutableRefObject<Record<string, HTMLButtonElement | null>>
  filtersRef: MutableRefObject<HTMLDivElement | null>

  // Mobile
  isMobile: boolean
  tabsRef: MutableRefObject<HTMLDivElement | null>
}

const FilterBarContext = createContext<FilterBarContextType | undefined>(
  undefined
)

export const FilterBarProvider = ({
  children,
  language,
  ageCategories,
  redirectUrl,
  palette,
  onSubmit,
  fullWidth,
  disableCalendarDates,
  mode,
  tabs,
  outerLoading,
  locations,
}: FilterBarProviderProps) => {
  const {
    selectedPath,
    selectedFilter,
    calendarRange,
    innerLoading,
    categories,
    ageCategoryCounts,
    selectedLocations,
    setSelectedLocations,
    setCalendarRange,
    setAgeCategoryCounts,
    setCategories,
    setSelectedPath,
    setSelectedFilter,
    setInnerLoading,
  } = useFilterState({ locations })

  const filterActions = useFilterActions({
    tabs,
    ageCategoryCounts,
    ageCategories,
    selectedLocations,
    selectedPath,
    redirectUrl,
    calendarRange,
    setSelectedPath,
    setAgeCategoryCounts,
    setSelectedFilter,
    setCalendarRange,
    onSubmit,
    setInnerLoading,
  })

  const filterRefs = useFilterRefs(selectedFilter)

  const contextValue = useMemo(
    () => ({
      selectedFilter,
      ageCategoryCounts,
      categories,
      calendarRange,
      selectedPath,
      innerLoading,
      selectedLocations,

      setSelectedLocations,
      setCalendarRange,
      setSelectedFilter,
      setAgeCategoryCounts,
      setCategories,
      setSelectedPath,

      ...filterActions,

      language,
      ageCategories,
      redirectUrl,
      palette,
      onSubmit,
      fullWidth,
      disableCalendarDates,
      mode,
      tabs,
      outerLoading,
      locations,

      ...filterRefs,
    }),
    [
      selectedFilter,
      ageCategoryCounts,
      categories,
      calendarRange,
      selectedPath,
      innerLoading,
      selectedLocations,
      language,
      ageCategories,
      redirectUrl,
      palette,
      onSubmit,
      fullWidth,
      disableCalendarDates,
      mode,
      tabs,
      outerLoading,
      locations,
      filterRefs.isMobile,
      filterRefs.tabsRef,
      filterRefs.filtersRef,
    ]
  )

  return (
    <FilterBarContext.Provider value={contextValue}>
      {children}
    </FilterBarContext.Provider>
  )
}

export const useFilterBar = () => {
  const context = useContext(FilterBarContext)
  if (!context) {
    throw new Error('useFilterBar must be used within FilterBarProvider')
  }
  return context
}
