// TODO: タグ入力系すべてに同様の処理あるため共通化する．

import { useEffect, useState } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'

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

import TagSearchBox from './TagSearchBox'

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

import type { Tag } from '@/types'


const TagSearch: FC = () => {
  const location = useLocation ()
  const navigate = useNavigate ()

  const [activeIndex, setActiveIndex] = useState (-1)
  const [search, setSearch] = useState ('')
  const [suggestions, setSuggestions] = useState<Tag[]> ([])
  const [suggestionsVsbl, setSuggestionsVsbl] = useState (false)

  const whenChanged = async (ev: ChangeEvent<HTMLInputElement>) => {
    setSearch (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 } })
    setSuggestions (data.filter (t => t.postCount > 0))
    if (suggestions.length > 0)
      setSuggestionsVsbl (true)
  }

  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))
      {
	const parts = search.split (' ')
	const match = parts.map (t => t.toLowerCase ()).includes ('type:or') ? 'any' : 'all'
	navigate (`/posts?${
	    (new URLSearchParams ({
		tags: parts.map (t => t.toLowerCase ())
			   .filter (t => t !== 'type:or')
			   .join (' '),
		match }))
	    .toString () }`)
	setSuggestionsVsbl (false)
      }
  }

  const handleTagSelect = (tag: Tag) => {
    const parts = search.split (' ')
    parts[parts.length - 1] = (
	(parts[parts.length - 1].slice(0, 4).toLowerCase () === 'not:')
	? ('not:' + tag.name)
	: tag.name)
    setSearch (parts.join (' ') + ' ')
    setSuggestions ([])
    setActiveIndex (-1)
  }

  useEffect (() => {
    const query = new URLSearchParams (location.search)
    const anyFlg = query.get ('match') === 'any'
    const tagsQuery = `${ query.get ('tags') ?? '' }${ anyFlg ? ' type:or' : '' }`
    setSearch (tagsQuery)
  }, [location.search])

  return (
      <div className="relative w-full">
	<input type="text"
	       data-shortcut-focus-search="true"
	       placeholder="タグ検索..."
	       value={search}
	       onChange={whenChanged}
	       onFocus={() => setSuggestionsVsbl (true)}
	       onBlur={() => setSuggestionsVsbl (false)}
	       onKeyDown={handleKeyDown}
	       className={inputClass (false,
				      'px-3 py-2 dark:border-gray-600 dark:bg-gray-800 dark:text-white')}/>
	<TagSearchBox suggestions={suggestionsVsbl && suggestions.length ? suggestions : [] as Tag[]}
		      activeIndex={activeIndex}
		      onSelect={handleTagSelect}/>
      </div>)
}

export default TagSearch
