import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { Helmet } from 'react-helmet-async'
import { useLocation, useNavigate } from 'react-router-dom'

import FieldError from '@/components/common/FieldError'
import Form from '@/components/common/Form'
import FormField from '@/components/common/FormField'
import PageTitle from '@/components/common/PageTitle'
import TagInput from '@/components/common/TagInput'
import MainArea from '@/components/layout/MainArea'
import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config'
import { createMaterial } from '@/lib/materials'
import { materialsKeys } from '@/lib/queryKeys'
import { inputClass } from '@/lib/utils'
import { useValidationErrors } from '@/lib/useValidationErrors'

import type { FC } from 'react'

type MaterialFormField = 'tag' | 'file' | 'url' | 'exportPaths'


const MaterialNewPage: FC = () => {
  const qc = useQueryClient ()
  const location = useLocation ()
  const query = new URLSearchParams (location.search)
  const tagQuery = query.get ('tag') ?? ''
  const returnToQuery = query.get ('return_to') ?? ''
  const safeReturnTo = returnToQuery.startsWith ('/materials') ? returnToQuery : ''

  const navigate = useNavigate ()

  const [file, setFile] = useState<File | null> (null)
  const [filePreview, setFilePreview] = useState ('')
  const [tag, setTag] = useState (tagQuery)
  const [url, setURL] = useState ('')
  const [exportPath, setExportPath] = useState ('')
  const { baseErrors, fieldErrors, clearValidationErrors, applyValidationError } =
      useValidationErrors<MaterialFormField> ()

  const createMutation = useMutation ({
      mutationFn: async () => {
	const formData = new FormData
	if (tag)
	  formData.append ('tag', tag)
	if (file)
	  formData.append ('file', file)
	if (url)
	  formData.append ('url', url)
	formData.append ('export_paths[legacy_drive]', exportPath)

	return await createMaterial (formData)
      },
      onSuccess: async () => {
	await qc.invalidateQueries ({ queryKey: materialsKeys.root })
	toast ({ title: '送信成功!' })
	navigate (safeReturnTo || '/materials')
      },
      onError: error => {
	applyValidationError (error)
	toast ({ title: '送信失敗……', description: '入力を見直してください．' })
      }})

  const handleSubmit = () => {
    clearValidationErrors ()
    createMutation.mutate ()
  }

  return (
      <MainArea>
	<Helmet>
	  <title>{`素材追加 | ${ SITE_TITLE }`}</title>
	</Helmet>

	<Form>
	  <PageTitle>素材追加</PageTitle>
	  <FieldError messages={baseErrors}/>

	  {/* タグ */}
	   <FormField label="タグ" messages={fieldErrors.tag}>
	    {({ describedBy, invalid }) => (
		<TagInput
		    describedBy={describedBy}
		    invalid={invalid}
		    value={tag}
		    setValue={setTag}/>)}
	  </FormField>

	  {/* ファイル */}
	  <FormField label="ファイル" messages={fieldErrors.file}>
	    {({ describedBy, invalid }) => (
		<>
		  <input
		      type="file"
		      accept="image/*,video/*,audio/*"
		      aria-describedby={describedBy}
		      aria-invalid={invalid}
		      onChange={e => {
			const f = e.target.files?.[0]
			setFile (f ?? null)
			setFilePreview (f ? URL.createObjectURL (f) : '')
		      }}/>
		  {(file && filePreview) && (
		      (/image\/.*/.test (file.type) && (
			  <img
			      src={filePreview}
			      alt="preview"
			      className="mt-2 max-h-48 rounded border"/>))
		      || (/video\/.*/.test (file.type) && (
			  <video
			      src={filePreview}
			      controls
			      className="mt-2 max-h-48 rounded border"/>))
		      || (/audio\/.*/.test (file.type) && (
			  <audio
			      src={filePreview}
			      controls
			      className="mt-2 max-h-48"/>))
		      || (
			  <p className="text-red-600 dark:text-red-400">
			    その形式のファイルには対応していません．
			  </p>))}
		</>)}
	  </FormField>

	  {/* 参考 URL */}
	  <FormField label="参考 URL" messages={fieldErrors.url}>
	    {({ describedBy, invalid }) => (
		<input
		    type="url"
		    value={url}
		    onChange={e => setURL (e.target.value)}
		    aria-describedby={describedBy}
		    aria-invalid={invalid}
		    className={inputClass (invalid)}/>)}
	  </FormField>

	  <FormField
	      label="ZIP 出力パス"
	      messages={fieldErrors.exportPaths}>
	    {({ describedBy, invalid }) => (
		<input
		    type="text"
		    value={exportPath}
		    onChange={e => setExportPath (e.target.value)}
		    placeholder="伊地知ニジカ/表情/泣き.png"
		    aria-describedby={describedBy}
		    aria-invalid={invalid}
		    className={inputClass (invalid)}/>)}
	  </FormField>

	  {/* 送信 */}
	  <Button
	      onClick={handleSubmit}
	      className="px-4 py-2 bg-blue-600 text-white rounded disabled:bg-gray-400"
	      disabled={createMutation.isPending}>
	    追加
	  </Button>
	</Form>
      </MainArea>)
}

export default MaterialNewPage
