import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'

import TagLink from '@/components/TagLink'
import FieldError from '@/components/common/FieldError'
import FormField from '@/components/common/FormField'
import PageTitle from '@/components/common/PageTitle'
import MainArea from '@/components/layout/MainArea'
import { toast } from '@/components/ui/use-toast'
import { CATEGORIES, CATEGORY_NAMES } from '@/consts'
import { apiPut } from '@/lib/api'
import { postsKeys, tagsKeys } from '@/lib/queryKeys'
import { fetchTag } from '@/lib/tags'
import { cn, inputClass } from '@/lib/utils'
import { useValidationErrors } from '@/lib/useValidationErrors'

import type { FC, FormEvent } from 'react'

import type { Category, Tag } from '@/types'

type TagFormField =
    | 'name'
    | 'category'
    | 'aliases'
    | 'parentTags'
    | 'deprecated'


const TagDetailPage: FC = () => {
  const { id } = useParams ()
  const tagId = String (id ?? '')
  const tagKey = tagsKeys.show (tagId)

  const { data: tag, isLoading: loading } = useQuery ({
      queryKey: tagKey,
      queryFn: () => fetchTag (tagId) })

  const [name, setName] = useState ('')
  const [category, setCategory] = useState<Category> ('general')
  const [aliases, setAliases] = useState ('')
  const [parentTags, setParentTags] = useState ('')
  const [deprecated, setDeprecated] = useState (false)
  const [disabled, setDisabled] = useState (true)
  const { baseErrors, fieldErrors, clearValidationErrors, applyValidationError } =
      useValidationErrors<TagFormField> ()

  const qc = useQueryClient ()

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault ()
    clearValidationErrors ()

    const formData = new FormData
    formData.append ('name', name)
    formData.append ('category', category)
    formData.append ('aliases', aliases)
    formData.append ('parent_tags', parentTags)
    formData.append ('deprecated', deprecated ? '1' : '0')

    try
    {
      const data = await apiPut<Tag> (`/tags/${ id }`, formData)

      setName (data.name)
      setCategory (data.category as Category)
      setAliases (data.aliases.join (' '))
      setParentTags (data.parents.map (t => t.name).join (' '))
      setDeprecated (Boolean (data.deprecatedAt))

      qc.invalidateQueries ({ queryKey: postsKeys.root })
      qc.invalidateQueries ({ queryKey: tagsKeys.root })
      toast ({ description: '更新しました．' })
    }
    catch (e)
    {
      applyValidationError (e)
      toast ({ description: '更新に失敗しました．' })
    }
  }

  useEffect (() => {
    if (!(tag))
      {
	setDisabled (true)
	return
      }

    setName (tag.name)
    setCategory (tag.category as Category)
    setAliases (tag.aliases.join (' '))
    setParentTags (tag.parents.map (t => t.name).join (' '))
    setDeprecated (Boolean (tag.deprecatedAt))
    setDisabled (tag.category === 'nico')
  }, [tag])

  return (
      <MainArea>
	{(loading || !(tag)) ? 'Loading...' : (
	    <div className="max-w-xl">
	      <PageTitle>
		<TagLink
		    tag={tag}
		    withWiki={false}
		    withCount={false}/>
	      </PageTitle>

	      <form onSubmit={handleSubmit} className="my-4 space-y-2">
		<FieldError messages={baseErrors}/>

		{/* 名称 */}
		<FormField label="名称" messages={fieldErrors.name}>
		  {({ describedBy, invalid }) => (
		      <>
			{/* TODO: 補完に対応させる */}
			<input
			    type="text"
			    disabled={disabled}
			    value={name}
			    onChange={e => setName (e.target.value)}
			    aria-describedby={describedBy}
			    aria-invalid={invalid}
			    className={inputClass (invalid)}/>
		      </>)}
		</FormField>

		{/* カテゴリ */}
		<FormField label="カテゴリ" messages={fieldErrors.category}>
		  {({ describedBy, invalid }) => (
		  <select
		      disabled={disabled}
		      value={category ?? ''}
		      onChange={e => setCategory(e.target.value as Category)}
		      aria-describedby={describedBy}
		      aria-invalid={invalid}
		      className={inputClass (invalid)}>
		    {CATEGORIES.filter (cat => tag.category === 'nico' || cat !== 'nico')
			       .map (cat => (
			<option key={cat} value={cat}>
			  {CATEGORY_NAMES[cat]}
			</option>))}
		  </select>)}
		</FormField>

		{/* 別名 */}
		<FormField label="別名" messages={fieldErrors.aliases}>
		  {({ describedBy, invalid }) => (
		      <>
			{/* TODO: 補完に対応させる */}
			<input
			    type="text"
			    disabled={disabled}
			    value={aliases}
			    onChange={e => setAliases (e.target.value)}
			    aria-describedby={describedBy}
			    aria-invalid={invalid}
			    className={inputClass (invalid)}/>
		      </>)}
		</FormField>

		{/* 上位タグ */}
		<FormField label="上位タグ" messages={fieldErrors.parentTags}>
		  {({ describedBy, invalid }) => (
		      <>
			{/* TODO: 補完に対応させる */}
			<input
			    type="text"
			    disabled={disabled}
			    value={parentTags}
			    onChange={e => setParentTags (e.target.value)}
			    aria-describedby={describedBy}
			    aria-invalid={invalid}
			    className={inputClass (invalid)}/>
		      </>)}
		</FormField>

		<FormField label="廃止済" messages={fieldErrors.deprecated}>
		  {({ describedBy, invalid }) => (
		      <input
			  type="checkbox"
			  disabled={disabled}
			  checked={deprecated}
			  onChange={e => setDeprecated (e.target.checked)}
			  aria-describedby={describedBy}
			  aria-invalid={invalid}/>)}
		</FormField>

		<div className="py-3">
		  <button
		      type="submit"
		      disabled={disabled}
		      className={cn ('px-4 py-2 rounded',
				     (disabled
				      ? 'text-gray-300 bg-gray-500'
				      : 'text-white bg-blue-500'))}>
		    更新
		  </button>
		</div>
	      </form>
	    </div>)}
      </MainArea>)
}

export default TagDetailPage
