import { Button } from '@headlessui/react'
import { zodResolver } from '@hookform/resolvers/zod'
import { useEffect, useState, type ChangeEvent } from 'react'
import { useFetcher } from 'react-router'
import { RemixFormProvider, useRemixForm } from 'remix-hook-form'
import { z } from 'zod'

import { uploadCategorySchema, useAdminContext } from '~/contexts/admin'

export const uploadSchema = z.object({
  file: z.instanceof(File),
  category: uploadCategorySchema,
})

export type TUploadSchema = z.infer<typeof uploadSchema>

export const FormUpload = () => {
  const { isUploadOpen, setUploadedFile, setIsUploadOpen } = useAdminContext()
  const fetcher = useFetcher()
  const [disabled, setDisabled] = useState(false)
  const [error, setError] = useState<string>()
  const maxFileSize = 1024 // 1MB

  const formMethods = useRemixForm<TUploadSchema>({
    mode: 'onSubmit',
    fetcher,
    resolver: zodResolver(uploadSchema),
  })

  const { handleSubmit, register, setValue } = formMethods

  useEffect(() => {
    if (!fetcher.data?.success) {
      setError(fetcher.data?.message)
      setDisabled(false)
      return
    }

    setUploadedFile(fetcher.data.uploadData.data.file_url)
    setIsUploadOpen(undefined)

    setDisabled(true)
    setError(undefined)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [fetcher])

  const handleChange = async function (event: ChangeEvent<HTMLInputElement>) {
    event.preventDefault()
    if (event.target.files && event.target.files[0]) {
      const files: File[] = [...event.target.files]

      onChange(files, event)
    }
  }

  const onChange = async function (
    files: File[],
    event: ChangeEvent<HTMLInputElement>,
  ) {
    const file = files[0]
    const img = new Image()

    if (!file.type.startsWith('image/')) {
      setError('Please upload an image file.')
      return
    }

    if (file.size > maxFileSize * 1024) {
      setError(`File size is too big!`)
      return
    }

    img.addEventListener('load', () => {
      handleFiles(event)
    })

    img.src = URL.createObjectURL(file)
  }

  const handleFiles = (event: ChangeEvent<HTMLInputElement>) => {
    const files = event.target.files
    if (files && files.length > 0) {
      const file = files[0]
      setValue('file', file)
    }
  }

  return (
    <RemixFormProvider {...formMethods}>
      <fetcher.Form
        method="post"
        onSubmit={handleSubmit}
        className="space-y-4"
        action="/actions/admin/upload"
        encType="multipart/form-data"
      >
        {error && (
          <div className="text-sm text-red-500 capitalize">{error}</div>
        )}
        <input
          type="file"
          id="input-file-upload"
          accept="image/*"
          onChange={handleChange}
        />
        <input
          type="hidden"
          id="input-file-upload-type"
          value={isUploadOpen}
          {...register('category')}
        />
        <Button
          disabled={disabled}
          type="submit"
          className="w-full rounded-md bg-[#2E2F7C] py-2 text-white transition hover:bg-blue-800"
        >
          Upload
        </Button>
      </fetcher.Form>
    </RemixFormProvider>
  )
}
