import React, { useState, useEffect, useRef } from "react"
import PropTypes from "prop-types"
import Button from "../button"
import FilterGroup from "./filter-group"
import FilterTypeContext from "./filter-type-context"

const initialState = [
  {
    type: "collections/all",
    filters: [],
  },
]

function useFocus() {
  const ref = useRef()
  const [focusKey, setFocusKey] = useState()

  useEffect(() => {
    if (focusKey) ref.current.focus()
  }, [focusKey])

  const focus = () => {
    setFocusKey({})
  }

  return [ref, focus]
}

function Splitter() {
  return (
    <div className="text-center text-xs text-gray-300 my-1 flex items-center justify-center">
      <span className="block border-t border-gray-300 w-4"></span>
      <div className="mx-2 uppercase">and</div>
      <span className="block border-t border-gray-300 w-4"></span>
    </div>
  )
}

function Filter({
  className,
  types = [],
  filters = initialState,
  onChange,
  size = "",
}) {
  const [lastGroup, focusLastGroup] = useFocus()

  // If an empty array is passed as the `filters` prop, we still display one
  // group so the user doesn't have to click "Add Filter Group", and then
  // "Add Filter".
  const groups = filters.length > 0 ? filters : initialState

  const addGroup = () => {
    onChange([...groups, { type: "collections/any", filters: [] }])
    focusLastGroup()
  }

  const removeGroup = groupIndex => {
    onChange(groups.filter((group, i) => i !== groupIndex))
  }

  const updateGroup = (groupIndex, attrs) => {
    const newGroups = groups.map((group, index) => {
      if (index !== groupIndex) return group
      return { ...group, ...attrs }
    })
    onChange(newGroups)
  }

  const changeGroupType = (groupIndex, type) => {
    updateGroup(groupIndex, { type })
  }

  const addFilter = (groupIndex, filter) => {
    const newFilters = [...groups[groupIndex].filters, filter]
    updateGroup(groupIndex, { filters: newFilters })
  }

  const saveFilter = (groupIndex, filterIndex, updatedFilter) => {
    const newFilters = groups[groupIndex].filters.map((filter, index) => {
      if (index !== filterIndex) return filter
      return updatedFilter
    })

    updateGroup(groupIndex, { filters: newFilters })
  }

  const removeFilter = (groupIndex, filterIndex) => {
    const newFilters = groups[groupIndex].filters.filter(
      (filter, index) => index !== filterIndex
    )

    updateGroup(groupIndex, { filters: newFilters })
  }

  return (
    <FilterTypeContext.Provider value={types}>
      <div className={className}>
        {groups.map((group, index) => (
          <React.Fragment key={index}>
            {groups.length > 1 && index > 0 && <Splitter />}
            <FilterGroup
              removable={groups.length > 1}
              onChangeType={changeGroupType}
              onRemove={() => removeGroup(index)}
              onAddFilter={addFilter}
              onSaveFilter={saveFilter}
              onRemoveFilter={removeFilter}
              index={index}
              ref={lastGroup}
              size={size}
              {...group}
            />
          </React.Fragment>
        ))}
        <Button className="mt-4 w-full" is="secondary" size="lg" onClick={addGroup} type="button">
          Add Filter Group
        </Button>
      </div>
    </FilterTypeContext.Provider>
  )
}

Filter.propTypes = {
  className: PropTypes.string,
  types: PropTypes.array,
  filters: PropTypes.array,
  onChange: PropTypes.func,
  size: PropTypes.string
}

export default Filter
