import { h, type FunctionComponent } from 'preact'
import { useCallback, useRef, useState } from 'preact/hooks'
import cn from 'classnames'

// TODO when form resets after update the previous image flashes quickly after setImageSrc(null) and before new defaultValue propagates

type Styles = {
  base?: string
  element?: string
  label?: string
  noMargin?: string
  touched?: string
  image?: string
}

type Options = {
  styles: Styles
}

type Props = {
  autoFocus?: boolean
  className?: string
  defaultValue?: any
  disabled?: boolean
  label?: string
  name?: string
  noMargin?: boolean
  placeholder?: string
  required?: boolean
}

export default function fileUploadFactory({ styles }: Options) {
  const FileUpload: FunctionComponent<Props> = ({
    autoFocus,
    className,
    defaultValue,
    disabled,
    label,
    name,
    noMargin,
    placeholder,
    required,
  }) => {
    const [touched, setTouched] = useState(false)
    const inputRef = useRef<HTMLInputElement>(null)
    const imgRef = useRef<HTMLImageElement>(null)
    const [imageSrc, setImageSrc] = useState<string | null>(null)

    const onImageChange = useCallback((e: Event) => {
      e.preventDefault()

      const form = inputRef.current!.form!

      const onReset = () => {
        setTouched(false)
        setImageSrc(null)
      }

      form.addEventListener('reset', onReset)

      imgRef.current!.addEventListener('load', () => URL.revokeObjectURL(imgRef.current!.src), { once: true })
      setImageSrc(URL.createObjectURL((e.currentTarget! as HTMLInputElement).files![0]))

      return () => form.removeEventListerner('reset', onReset)
    }, [])

    return (
      <div className={cn(styles.base, noMargin && styles.noMargin, touched && styles.touched, className)}>
        <input
          type='file'
          accept='image/*'
          name={name}
          ref={inputRef}
          className={styles.element}
          onChange={onImageChange}
          autoFocus={autoFocus}
          disabled={disabled}
          placeholder={placeholder}
          required={required}
          defaultValue={defaultValue}
        />
        <label htmlFor={name} className={styles.label}>
          {label}
        </label>
        <figure className={styles.image}>
          <img className={styles.image} src={imageSrc || (defaultValue && `/uploads/${defaultValue}`)} ref={imgRef} />
        </figure>
      </div>
    )
  }

  return FileUpload
}
