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

type CheckboxStyles<S extends string> = {
  base?: string
  element?: string
  label?: string
  touched?: string
} & Record<S, string>

type CheckboxProps<S extends string> = {
  autoFocus?: boolean
  className?: string
  defaultChecked?: any
  disabled?: boolean
  label?: string
  name?: string
  onChange?: (e: ChangeEvent) => void
  required?: boolean
  style?: S
  value?: string
}

export default function checkboxFactory<S extends string = never>(styles: CheckboxStyles<S>) {
  const Checkbox: FunctionComponent<CheckboxProps<S>> = ({
    autoFocus,
    className,
    defaultChecked,
    disabled,
    name,
    label,
    onChange,
    required,
    style,
    value = 'true',
  }) => {
    const [touched, setTouched] = useState(false)
    const checkboxRef = useRef<HTMLInputElement>(null)

    const onBlur = useCallback(() => setTouched(true), [])

    useEffect(() => {
      const form = checkboxRef.current!.form!
      const resetTouched = setTouched.bind(null, false)

      form.addEventListener('reset', resetTouched)

      return () => form.removeEventListener('reset', resetTouched)
    }, [])

    useEffect(() => {
      if (autoFocus) checkboxRef.current!.focus()
    }, [autoFocus])

    return (
      <label className={cn(styles.base, style && styles[style], touched && styles.touched, className)}>
        <input
          autoFocus={autoFocus}
          className={styles.element}
          defaultChecked={defaultChecked}
          disabled={disabled}
          name={name}
          onBlur={onBlur}
          onChange={onChange}
          ref={checkboxRef}
          required={required}
          type='checkbox'
          value={value}
        />

        <i />

        {label && <span className={styles.label}>{label}</span>}
      </label>
    )
  }

  return Checkbox
}
