import { useState } from 'react'

import TagSearchBox from '@/components/TagSearchBox'
import { apiGet } from '@/lib/api'
import { inputClass } from '@/lib/utils'

import type { FC, ChangeEvent, KeyboardEvent } from 'react'

import type { Tag } from '@/types'


type Props = {
    includeNico?:   boolean
    describedBy?:  string
    invalid?:      boolean
    value:         string
    setValue:      (value: string) => void }


const TagInput: FC<Props> = ({
    includeNico = false,
    describedBy,
    invalid,
    value,
    setValue,
}) => {
  const [activeIndex, setActiveIndex] = useState (-1)
  const [suggestions, setSuggestions] = useState<Tag[]> ([])
  const [suggestionsVsbl, setSuggestionsVsbl] = useState (false)

  // TODO: TagSearch からのコピペのため，共通化を考へる．
  const whenChanged = async (ev: ChangeEvent<HTMLInputElement>) => {
    setValue (ev.target.value)

    const q = ev.target.value.trim ().split (' ').at (-1)
    if (!(q))
      {
	setSuggestions ([])
	return
      }

    const data = await apiGet<Tag[]> ('/tags/autocomplete', { params: {
	q,
	nico: includeNico ? '1' : '0' } })
    const nextSuggestions = data.filter (t => t.postCount > 0)
    setSuggestions (nextSuggestions)
    setSuggestionsVsbl (nextSuggestions.length > 0)
  }

  // TODO: TagSearch からのコピペのため，共通化を考へる．
  const handleTagSelect = (tag: Tag) => {
    const parts = value?.split (' ')
    parts[parts.length - 1] = tag.name
    setValue (parts.join (' ') + ' ')
    setSuggestions ([])
    setActiveIndex (-1)
  }

  // TODO: TagSearch からのコピペのため，共通化を考へる．
  const handleKeyDown = (ev: KeyboardEvent<HTMLInputElement>) => {
    switch (ev.key)
    {
    case 'ArrowDown':
      ev.preventDefault ()
      setActiveIndex (i => Math.min (i + 1, suggestions.length - 1))
      setSuggestionsVsbl (true)
      break

    case 'ArrowUp':
      ev.preventDefault ()
      setActiveIndex (i => Math.max (i - 1, -1))
      setSuggestionsVsbl (true)
      break

    case 'Enter':
      if (activeIndex < 0)
	break
      {
	ev.preventDefault ()
	const selected = suggestions[activeIndex]
	if (selected)
	  handleTagSelect (selected)
      }
      break

    case 'Escape':
      ev.preventDefault ()
      setSuggestionsVsbl (false)
      break
    }
    if (ev.key === 'Enter' && (!(suggestionsVsbl) || activeIndex < 0))
      {
	setSuggestionsVsbl (false)
      }
  }

  return (
      <div className="relative">
	<input
	    type="text"
	    aria-describedby={describedBy}
	    aria-invalid={invalid}
	    value={value}
	    onChange={whenChanged}
	    onFocus={() => setSuggestionsVsbl (true)}
	    onBlur={() => setSuggestionsVsbl (false)}
	    onKeyDown={handleKeyDown}
	    className={inputClass (invalid)}/>
	<TagSearchBox
	    suggestions={
		suggestionsVsbl && suggestions.length > 0 ? suggestions : [] as Tag[]}
	    activeIndex={activeIndex}
	    onSelect={handleTagSelect}/>
      </div>)
}

export default TagInput
