import React, { useState, useEffect, useRef } from 'react'
import { SearchIcon } from './SearchIcon'
import { ClearButton } from './ClearButton'
import { Input } from './ui'
import { SearchSuggestions } from './SearchSuggestions'
import { saveSearchQuery } from '@/lib/searchHistory'
import { t } from '@/lib/i18n'

interface SearchBarProps {
  value: string
  onChange: (value: string) => void
  placeholder?: string
}

function useSearchBarLocalValue(value: string): [string, (value: string) => void] {
  const [localValue, setLocalValue] = useState(value)
  useEffect(() => {
    setLocalValue(value)
  }, [value])
  return [localValue, setLocalValue]
}

function useSearchBarFocusState(): [boolean, () => void, () => void] {
  const [isFocused, setIsFocused] = useState(false)
  const handleFocus = (): void => {
    setIsFocused(true)
  }
  const handleBlur = (): void => {
    setIsFocused(false)
  }
  return [isFocused, handleFocus, handleBlur]
}

interface UseSearchBarHandlersParams {
  setLocalValue: (value: string) => void
  onChange: (value: string) => void
  isFocused: boolean
  setShowSuggestions: (show: boolean) => void
}

function useSearchBarHandlers(params: UseSearchBarHandlersParams): {
  handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void
  handleClear: () => void
  handleFocusWithSuggestions: () => void
  handleSelectSuggestion: (query: string) => void
  handleCloseSuggestions: () => void
} {
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
    const newValue = e.target.value
    params.setLocalValue(newValue)
    params.onChange(newValue)
    if (newValue.trim() && params.isFocused) {
      params.setShowSuggestions(true)
    }
  }

  const handleClear = (): void => {
    params.setLocalValue('')
    params.onChange('')
    params.setShowSuggestions(false)
  }

  const handleFocusWithSuggestions = (): void => {
    params.setShowSuggestions(true)
  }

  const handleSelectSuggestion = (query: string): void => {
    params.setLocalValue(query)
    params.onChange(query)
    params.setShowSuggestions(false)
    void saveSearchQuery(query)
  }

  const handleCloseSuggestions = (): void => {
    params.setShowSuggestions(false)
  }

  return {
    handleChange,
    handleClear,
    handleFocusWithSuggestions,
    handleSelectSuggestion,
    handleCloseSuggestions,
  }
}

function useSearchBarState(value: string, onChange: (value: string) => void): {
  localValue: string
  showSuggestions: boolean
  handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void
  handleClear: () => void
  handleFocus: () => void
  handleBlur: () => void
  handleSelectSuggestion: (query: string) => void
  handleCloseSuggestions: () => void
  setShowSuggestions: (show: boolean) => void
} {
  const [localValue, setLocalValue] = useSearchBarLocalValue(value)
  const [showSuggestions, setShowSuggestions] = useState(false)
  const [isFocused, , handleBlur] = useSearchBarFocusState()
  const handlers = useSearchBarHandlers({ setLocalValue, onChange, isFocused, setShowSuggestions })

  return {
    localValue,
    showSuggestions,
    handleChange: handlers.handleChange,
    handleClear: handlers.handleClear,
    handleFocus: handlers.handleFocusWithSuggestions,
    handleBlur,
    handleSelectSuggestion: handlers.handleSelectSuggestion,
    handleCloseSuggestions: handlers.handleCloseSuggestions,
    setShowSuggestions,
  }
}

function useClickOutsideHandler(containerRef: React.RefObject<HTMLDivElement | null>, showSuggestions: boolean, setShowSuggestions: (show: boolean) => void): void {
  useEffect(() => {
    if (!showSuggestions) {
      return
    }
    const handleClickOutside = (e: MouseEvent): void => {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setShowSuggestions(false)
      }
    }
    document.addEventListener('mousedown', handleClickOutside)
    return () => {
      document.removeEventListener('mousedown', handleClickOutside)
    }
  }, [showSuggestions, setShowSuggestions, containerRef])
}

export const SearchBar = React.forwardRef<HTMLInputElement, SearchBarProps>(
  ({ value, onChange, placeholder }, ref): React.ReactElement => {
    const defaultPlaceholder = placeholder ?? t('search.placeholder')
    const containerRef = useRef<HTMLDivElement>(null)
    const {
      localValue,
      showSuggestions,
      handleChange,
      handleClear,
      handleFocus,
      handleBlur,
      handleSelectSuggestion,
      handleCloseSuggestions,
      setShowSuggestions,
    } = useSearchBarState(value, onChange)

    useClickOutsideHandler(containerRef, showSuggestions, setShowSuggestions)

    return (
      <div ref={containerRef} className="relative w-full">
        <Input
          ref={ref}
          type="text"
          value={localValue}
          onChange={handleChange}
          onFocus={handleFocus}
          onBlur={handleBlur}
          placeholder={defaultPlaceholder}
          leftIcon={<SearchIcon />}
          rightIcon={localValue ? <ClearButton onClick={handleClear} /> : undefined}
          className="pr-10"
          role="search"
          aria-label={t('search.placeholder')}
          aria-autocomplete="list"
          aria-expanded={showSuggestions}
        />
        {showSuggestions && (
          <SearchSuggestions query={localValue} onSelect={handleSelectSuggestion} onClose={handleCloseSuggestions} />
        )}
      </div>
    )
  }
)

SearchBar.displayName = 'SearchBar'
